Merge branch 'master' into k8s_end2end

This commit is contained in:
thompsonja 2016-04-01 14:55:21 -07:00
Родитель 40e9af53e3 0698355fb7
Коммит 8b5d02e69d
73 изменённых файлов: 4043 добавлений и 804 удалений

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

@ -6,6 +6,21 @@
"delete from nouser"
"table nouser not found"
# explicit keyspace reference
"update main.m1 set val = 1"
{
"Original": "update main.m1 set val = 1",
"Instructions": {
"Opcode": "UpdateUnsharded",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"Query": "update m1 set val = 1",
"Table": "m1"
}
}
# update unsharded
"update main1 set val = 1"
{

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

@ -790,6 +790,25 @@
}
}
# implicit table reference for unsharded keyspace
"select main.foo.col from main.foo"
{
"Original": "select main.foo.col from main.foo",
"Instructions": {
"Opcode": "SelectUnsharded",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"Query": "select foo.col from foo",
"FieldQuery": "select foo.col from foo where 1 != 1"
}
}
# implicit table reference for sharded keyspace
"select user.foo.col from user.foo"
"table foo not found"
# duplicate symbols
"select user.id from user join user"
"duplicate symbol: user"

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

@ -20,7 +20,7 @@
"Owner": "user"
}
},
"Classes": {
"Tables": {
"user": {
"ColVindexes": [
{
@ -77,23 +77,14 @@
}
]
}
},
"Tables": {
"user": "user",
"user_extra": "user_extra",
"music": "music",
"music_extra": "music_extra"
}
},
"main": {
"Classes": {
"Tables": {
"main1": {},
"seq": {
"Type": "Sequence"
}
},
"Tables": {
"main1": "",
"seq": "seq"
}
}
}

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

@ -146,10 +146,6 @@
"delete from user where col = (select id from main1)"
"unsupported: subqueries in DML"
# qualified table name in DMLs
"update u.user set id = 1"
"unsupported: compex table expression in DML"
# update with no where clause
"update user set val = 1"
"unsupported: multi-shard where clause in DML"

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

@ -28,7 +28,7 @@
"Type": "numeric"
}
},
"Classes": {
"Tables": {
"user": {
"ColVindexes": [
{
@ -89,26 +89,18 @@
}
]
}
},
"Tables": {
"user": "user",
"user_extra": "user_extra",
"music": "music",
"music_extra": "music_extra",
"music_user_idx": "music_user_idx"
}
},
"lookup": {
"Sharded": false,
"Classes": {
"seq": {
"Type": "Sequence"
}
},
"Tables": {
"user_seq": "seq",
"music_seq": "seq",
"name_user_idx": ""
"user_seq": {
"Type": "Sequence"
},
"music_seq": {
"Type": "Sequence"
},
"name_user_idx": {}
}
}
}

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

@ -362,6 +362,36 @@ func (itc *internalTabletConn) SplitQuery(ctx context.Context, query querytypes.
return splits, nil
}
// SplitQueryV2 is part of tabletconn.TabletConn
// TODO(erez): Rename to SplitQuery once the migration to SplitQuery V2 is done.
func (itc *internalTabletConn) SplitQueryV2(
ctx context.Context,
query querytypes.BoundQuery,
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]querytypes.QuerySplit, error) {
splits, err := itc.tablet.qsc.QueryService().SplitQueryV2(
ctx,
&querypb.Target{
Keyspace: itc.tablet.keyspace,
Shard: itc.tablet.shard,
TabletType: itc.tablet.tabletType,
},
query.Sql,
query.BindVariables,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm,
0 /* SessionID */)
if err != nil {
return nil, tabletconn.TabletErrorFromGRPC(tabletserver.ToGRPCError(err))
}
return splits, nil
}
type streamHealthReader struct {
c <-chan *querypb.StreamHealthResponse
err *error

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

@ -16,6 +16,7 @@ import (
"github.com/youtube/vitess/go/vt/callerid"
"github.com/youtube/vitess/go/vt/vtgate/vtgateservice"
querypb "github.com/youtube/vitess/go/vt/proto/query"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
vtgatepb "github.com/youtube/vitess/go/vt/proto/vtgate"
vtrpcpb "github.com/youtube/vitess/go/vt/proto/vtrpc"
@ -64,11 +65,11 @@ func (c *callerIDClient) checkCallerID(ctx context.Context, received string) (bo
return true, fmt.Errorf("SUCCESS: callerid matches")
}
func (c *callerIDClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
func (c *callerIDClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if ok, err := c.checkCallerID(ctx, sql); ok {
return nil, err
}
return c.fallbackClient.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction)
return c.fallbackClient.Execute(ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
}
func (c *callerIDClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
@ -117,11 +118,11 @@ func (c *callerIDClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []
return c.fallbackClient.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session)
}
func (c *callerIDClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
func (c *callerIDClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
if ok, err := c.checkCallerID(ctx, sql); ok {
return err
}
return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, tabletType, sendReply)
return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, keyspace, tabletType, sendReply)
}
func (c *callerIDClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
@ -151,3 +152,27 @@ func (c *callerIDClient) SplitQuery(ctx context.Context, keyspace string, sql st
}
return c.fallbackClient.SplitQuery(ctx, sql, keyspace, bindVariables, splitColumn, splitCount)
}
// TODO(erez): Rename after migration to SplitQuery V2 is done.
func (c *callerIDClient) SplitQueryV2(
ctx context.Context,
keyspace string,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]*vtgatepb.SplitQueryResponse_Part, error) {
if ok, err := c.checkCallerID(ctx, sql); ok {
return nil, err
}
return c.fallbackClient.SplitQueryV2(
ctx,
sql,
keyspace,
bindVariables,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm)
}

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

@ -86,18 +86,19 @@ func echoQueryResult(vals map[string]interface{}) *sqltypes.Result {
return qr
}
func (c *echoClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
func (c *echoClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if strings.HasPrefix(sql, EchoPrefix) {
return echoQueryResult(map[string]interface{}{
"callerId": callerid.EffectiveCallerIDFromContext(ctx),
"query": sql,
"bindVars": bindVariables,
"keyspace": keyspace,
"tabletType": tabletType,
"session": session,
"notInTransaction": notInTransaction,
}), nil
}
return c.fallbackClient.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction)
return c.fallbackClient.Execute(ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
}
func (c *echoClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
@ -205,17 +206,18 @@ func (c *echoClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vtg
return c.fallbackClient.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session)
}
func (c *echoClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
func (c *echoClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
if strings.HasPrefix(sql, EchoPrefix) {
sendReply(echoQueryResult(map[string]interface{}{
"callerId": callerid.EffectiveCallerIDFromContext(ctx),
"query": sql,
"bindVars": bindVariables,
"keyspace": keyspace,
"tabletType": tabletType,
}))
return nil
}
return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, tabletType, sendReply)
return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, keyspace, tabletType, sendReply)
}
func (c *echoClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
@ -283,3 +285,43 @@ func (c *echoClient) SplitQuery(ctx context.Context, keyspace string, sql string
}
return c.fallback.SplitQuery(ctx, sql, keyspace, bindVariables, splitColumn, splitCount)
}
// TODO(erez): Rename after migration to SplitQuery V2 is done.
func (c *echoClient) SplitQueryV2(
ctx context.Context,
keyspace string,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]*vtgatepb.SplitQueryResponse_Part, error) {
if strings.HasPrefix(sql, EchoPrefix) {
bv, err := querytypes.BindVariablesToProto3(bindVariables)
if err != nil {
return nil, err
}
return []*vtgatepb.SplitQueryResponse_Part{
{
Query: &querypb.BoundQuery{
Sql: fmt.Sprintf("%v:%v:%v:%v:%v",
sql, splitColumns, splitCount, numRowsPerQueryPart, algorithm),
BindVariables: bv,
},
KeyRangePart: &vtgatepb.SplitQueryResponse_KeyRangePart{
Keyspace: keyspace,
},
},
}, nil
}
return c.fallback.SplitQueryV2(
ctx,
sql,
keyspace,
bindVariables,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm)
}

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

@ -16,6 +16,7 @@ import (
"github.com/youtube/vitess/go/vt/vterrors"
"github.com/youtube/vitess/go/vt/vtgate/vtgateservice"
querypb "github.com/youtube/vitess/go/vt/proto/query"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
vtgatepb "github.com/youtube/vitess/go/vt/proto/vtgate"
vtrpcpb "github.com/youtube/vitess/go/vt/proto/vtrpc"
@ -117,14 +118,14 @@ func trimmedRequestToError(received string) error {
}
}
func (c *errorClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
func (c *errorClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if err := requestToPartialError(sql, session); err != nil {
return nil, err
}
if err := requestToError(sql); err != nil {
return nil, err
}
return c.fallbackClient.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction)
return c.fallbackClient.Execute(ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
}
func (c *errorClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
@ -191,11 +192,11 @@ func (c *errorClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vt
return c.fallbackClient.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session)
}
func (c *errorClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
func (c *errorClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
if err := requestToError(sql); err != nil {
return err
}
return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, tabletType, sendReply)
return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, keyspace, tabletType, sendReply)
}
func (c *errorClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
@ -256,6 +257,31 @@ func (c *errorClient) SplitQuery(ctx context.Context, keyspace string, sql strin
return c.fallbackClient.SplitQuery(ctx, sql, keyspace, bindVariables, splitColumn, splitCount)
}
// TODO(erez): Rename after migration to SplitQuery V2 is done.
func (c *errorClient) SplitQueryV2(
ctx context.Context,
keyspace string,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]*vtgatepb.SplitQueryResponse_Part, error) {
if err := requestToError(sql); err != nil {
return nil, err
}
return c.fallbackClient.SplitQueryV2(
ctx,
sql,
keyspace,
bindVariables,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm)
}
func (c *errorClient) GetSrvKeyspace(ctx context.Context, keyspace string) (*topodatapb.SrvKeyspace, error) {
if err := requestToError(keyspace); err != nil {
return nil, err

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

@ -10,6 +10,7 @@ import (
"github.com/youtube/vitess/go/sqltypes"
"github.com/youtube/vitess/go/vt/vtgate/vtgateservice"
querypb "github.com/youtube/vitess/go/vt/proto/query"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
vtgatepb "github.com/youtube/vitess/go/vt/proto/vtgate"
)
@ -26,8 +27,8 @@ func newFallbackClient(fallback vtgateservice.VTGateService) fallbackClient {
return fallbackClient{fallback: fallback}
}
func (c fallbackClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
return c.fallback.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction)
func (c fallbackClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
return c.fallback.Execute(ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
}
func (c fallbackClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
@ -54,8 +55,8 @@ func (c fallbackClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*
return c.fallback.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session)
}
func (c fallbackClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
return c.fallback.StreamExecute(ctx, sql, bindVariables, tabletType, sendReply)
func (c fallbackClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
return c.fallback.StreamExecute(ctx, sql, bindVariables, keyspace, tabletType, sendReply)
}
func (c fallbackClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
@ -86,6 +87,21 @@ func (c fallbackClient) SplitQuery(ctx context.Context, keyspace string, sql str
return c.fallback.SplitQuery(ctx, sql, keyspace, bindVariables, splitColumn, splitCount)
}
// TODO(erez): Rename after migration to SplitQuery V2 is done.
func (c fallbackClient) SplitQueryV2(
ctx context.Context,
keyspace string,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
) ([]*vtgatepb.SplitQueryResponse_Part, error) {
return c.fallback.SplitQueryV2(
ctx, sql, keyspace, bindVariables, splitColumns, splitCount, numRowsPerQueryPart, algorithm)
}
func (c fallbackClient) GetSrvKeyspace(ctx context.Context, keyspace string) (*topodatapb.SrvKeyspace, error) {
return c.fallback.GetSrvKeyspace(ctx, keyspace)
}

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

@ -14,6 +14,7 @@ import (
"github.com/youtube/vitess/go/tb"
"golang.org/x/net/context"
querypb "github.com/youtube/vitess/go/vt/proto/query"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
vtgatepb "github.com/youtube/vitess/go/vt/proto/vtgate"
)
@ -28,7 +29,7 @@ func newTerminalClient() *terminalClient {
return &terminalClient{}
}
func (c *terminalClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
func (c *terminalClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if sql == "quit://" {
log.Fatal("Received quit:// query. Going down.")
}
@ -59,7 +60,7 @@ func (c *terminalClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []
return nil, errTerminal
}
func (c *terminalClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
func (c *terminalClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
return errTerminal
}
@ -91,6 +92,20 @@ func (c *terminalClient) SplitQuery(ctx context.Context, keyspace string, sql st
return nil, errTerminal
}
// TODO(erez): Rename after migration to SplitQuery V2 is done.
func (c *terminalClient) SplitQueryV2(
ctx context.Context,
keyspace string,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
) ([]*vtgatepb.SplitQueryResponse_Part, error) {
return nil, errTerminal
}
func (c *terminalClient) GetSrvKeyspace(ctx context.Context, keyspace string) (*topodatapb.SrvKeyspace, error) {
return nil, errTerminal
}

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

@ -6,6 +6,7 @@ package stats
import (
"expvar"
"math/rand"
"reflect"
"sort"
"testing"
@ -122,6 +123,7 @@ func BenchmarkCounters(b *testing.B) {
func BenchmarkCountersTailLatency(b *testing.B) {
// For this one, ignore the time reported by 'go test'.
// The 99th Percentile log line is all that matters.
// (Cmd: go test -bench=BenchmarkCountersTailLatency -benchtime=30s -cpu=10)
clear()
benchCounter.Add("c1", 1)
c := make(chan time.Duration, 100)
@ -140,11 +142,15 @@ func BenchmarkCountersTailLatency(b *testing.B) {
}()
b.ResetTimer()
b.SetParallelism(1000)
b.SetParallelism(100) // The actual number of goroutines is 100*GOMAXPROCS
b.RunParallel(func(pb *testing.PB) {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
var start time.Time
for pb.Next() {
// sleep between 0~200ms to simulate 10 QPS per goroutine.
time.Sleep(time.Duration(r.Int63n(200)) * time.Millisecond)
start = time.Now()
benchCounter.Add("c1", 1)
c <- time.Since(start)

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

@ -362,6 +362,18 @@ func (fc *fakeConn) SplitQuery(ctx context.Context, query querytypes.BoundQuery,
return nil, fmt.Errorf("not implemented")
}
// SplitQueryV2 implements tabletconn.TabletConn.
func (fc *fakeConn) SplitQueryV2(
ctx context.Context,
query querytypes.BoundQuery,
splitColumn []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
) ([]querytypes.QuerySplit, error) {
return nil, fmt.Errorf("not implemented")
}
// SetTarget implements tabletconn.TabletConn.
func (fc *fakeConn) SetTarget(keyspace, shard string, tabletType topodatapb.TabletType) error {
return fmt.Errorf("not implemented")

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

@ -255,6 +255,29 @@ func (x Type) String() string {
}
func (Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
type SplitQueryRequest_Algorithm int32
const (
SplitQueryRequest_EQUAL_SPLITS SplitQueryRequest_Algorithm = 0
SplitQueryRequest_FULL_SCAN SplitQueryRequest_Algorithm = 1
)
var SplitQueryRequest_Algorithm_name = map[int32]string{
0: "EQUAL_SPLITS",
1: "FULL_SCAN",
}
var SplitQueryRequest_Algorithm_value = map[string]int32{
"EQUAL_SPLITS": 0,
"FULL_SCAN": 1,
}
func (x SplitQueryRequest_Algorithm) String() string {
return proto.EnumName(SplitQueryRequest_Algorithm_name, int32(x))
}
func (SplitQueryRequest_Algorithm) EnumDescriptor() ([]byte, []int) {
return fileDescriptor0, []int{22, 0}
}
// Target describes what the client expects the tablet is.
// If the tablet does not match, an error is returned.
type Target struct {
@ -749,15 +772,28 @@ func (m *RollbackResponse) String() string { return proto.CompactText
func (*RollbackResponse) ProtoMessage() {}
func (*RollbackResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{21} }
// SplitQueryRequest is the payload for SplitQuery
// SplitQueryRequest is the payload for SplitQuery sent by VTGate to a VTTablet.
// See vtgate.SplitQueryRequest for more details.
type SplitQueryRequest struct {
EffectiveCallerId *vtrpc.CallerID `protobuf:"bytes,1,opt,name=effective_caller_id,json=effectiveCallerId" json:"effective_caller_id,omitempty"`
ImmediateCallerId *VTGateCallerID `protobuf:"bytes,2,opt,name=immediate_caller_id,json=immediateCallerId" json:"immediate_caller_id,omitempty"`
Target *Target `protobuf:"bytes,3,opt,name=target" json:"target,omitempty"`
Query *BoundQuery `protobuf:"bytes,4,opt,name=query" json:"query,omitempty"`
SplitColumn string `protobuf:"bytes,5,opt,name=split_column,json=splitColumn" json:"split_column,omitempty"`
SplitCount int64 `protobuf:"varint,6,opt,name=split_count,json=splitCount" json:"split_count,omitempty"`
SessionId int64 `protobuf:"varint,7,opt,name=session_id,json=sessionId" json:"session_id,omitempty"`
SplitColumn []string `protobuf:"bytes,5,rep,name=split_column,json=splitColumn" json:"split_column,omitempty"`
// Exactly one of the following must be nonzero.
SplitCount int64 `protobuf:"varint,6,opt,name=split_count,json=splitCount" json:"split_count,omitempty"`
NumRowsPerQueryPart int64 `protobuf:"varint,8,opt,name=num_rows_per_query_part,json=numRowsPerQueryPart" json:"num_rows_per_query_part,omitempty"`
SessionId int64 `protobuf:"varint,7,opt,name=session_id,json=sessionId" json:"session_id,omitempty"`
Algorithm SplitQueryRequest_Algorithm `protobuf:"varint,9,opt,name=algorithm,enum=query.SplitQueryRequest_Algorithm" json:"algorithm,omitempty"`
// Whether to use the new split-query code
// that supports multiple split-columns and
// the FULL_SCAN algorithm.
// This is a temporary field which aids
// in the migration of SplitQuery to the new
// code.
// TODO(erez): Remove this field after the migration
// to the SplitQuery version 2.
UseSplitQueryV2 bool `protobuf:"varint,10,opt,name=use_split_query_v2,json=useSplitQueryV2" json:"use_split_query_v2,omitempty"`
}
func (m *SplitQueryRequest) Reset() { *m = SplitQueryRequest{} }
@ -945,104 +981,112 @@ func init() {
proto.RegisterType((*StreamHealthResponse)(nil), "query.StreamHealthResponse")
proto.RegisterEnum("query.Flag", Flag_name, Flag_value)
proto.RegisterEnum("query.Type", Type_name, Type_value)
proto.RegisterEnum("query.SplitQueryRequest_Algorithm", SplitQueryRequest_Algorithm_name, SplitQueryRequest_Algorithm_value)
}
var fileDescriptor0 = []byte{
// 1523 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe4, 0x58, 0xdb, 0x52, 0x1b, 0x47,
0x13, 0xfe, 0x57, 0x27, 0x44, 0x0b, 0x89, 0x65, 0x80, 0xbf, 0x28, 0xfe, 0x43, 0x9c, 0xb5, 0xe3,
0x38, 0xc4, 0x45, 0x11, 0xf9, 0x10, 0x57, 0xce, 0x12, 0x2c, 0x58, 0x15, 0x10, 0x78, 0xb4, 0xa2,
0xe2, 0xdc, 0x6c, 0x2d, 0xd2, 0x00, 0x5b, 0xac, 0xb4, 0x62, 0x77, 0x84, 0xcd, 0x1d, 0x49, 0x1c,
0xe7, 0xe8, 0x1c, 0x2a, 0x71, 0x8e, 0x97, 0xb9, 0xcf, 0x43, 0xe4, 0x01, 0x92, 0x17, 0x48, 0xe5,
0x3e, 0x57, 0x79, 0x85, 0xcc, 0x69, 0x97, 0x15, 0xe0, 0x50, 0xe5, 0xab, 0x38, 0xbe, 0xd2, 0x74,
0x7f, 0x3d, 0xd3, 0xdd, 0x5f, 0xf7, 0xcc, 0xec, 0x08, 0x0a, 0xbb, 0x7d, 0x12, 0xec, 0xcf, 0xf6,
0x02, 0x9f, 0xfa, 0x28, 0x2b, 0x84, 0xe9, 0x12, 0xf5, 0x7b, 0x7e, 0xdb, 0xa1, 0x8e, 0x54, 0x4f,
0x17, 0xf6, 0x68, 0xd0, 0x6b, 0x49, 0xc1, 0xd8, 0x85, 0x9c, 0xe5, 0x04, 0x5b, 0x84, 0xa2, 0x69,
0xc8, 0xef, 0x90, 0xfd, 0xb0, 0xe7, 0xb4, 0xc8, 0x94, 0x76, 0x46, 0xbb, 0x30, 0x8c, 0x63, 0x19,
0x4d, 0x40, 0x36, 0xdc, 0x76, 0x82, 0xf6, 0x54, 0x4a, 0x00, 0x52, 0x40, 0x57, 0xa0, 0x40, 0x9d,
0x0d, 0x8f, 0x50, 0x9b, 0xee, 0xf7, 0xc8, 0x54, 0x9a, 0x61, 0xa5, 0xf2, 0xc4, 0x6c, 0xec, 0xce,
0x12, 0xa0, 0xc5, 0x30, 0x0c, 0x34, 0x1e, 0x1b, 0x17, 0xa1, 0xb4, 0x6e, 0x2d, 0x39, 0x94, 0xcc,
0x3b, 0x9e, 0x47, 0x82, 0xda, 0x02, 0x77, 0xdd, 0x0f, 0x49, 0xd0, 0x75, 0x3a, 0xb1, 0xeb, 0x48,
0x36, 0x5e, 0x81, 0xec, 0xba, 0xe3, 0xf5, 0x09, 0x7a, 0x02, 0x32, 0xc2, 0x8d, 0x26, 0xdc, 0x14,
0x66, 0x65, 0xa6, 0x62, 0x75, 0x01, 0xf0, 0x20, 0xf7, 0xb8, 0xa5, 0x08, 0x72, 0x04, 0x4b, 0xc1,
0xd8, 0x81, 0x91, 0xaa, 0xdb, 0x6d, 0xaf, 0x3b, 0x81, 0xcb, 0x43, 0x78, 0xc8, 0x65, 0xd0, 0x39,
0xc8, 0x89, 0x41, 0xc8, 0xd2, 0x4c, 0x5f, 0x28, 0x94, 0x47, 0xd4, 0x44, 0x11, 0x1b, 0x56, 0x98,
0xf1, 0x93, 0x06, 0x50, 0xf5, 0xfb, 0xdd, 0xf6, 0x0d, 0x0e, 0x22, 0x1d, 0xd2, 0xe1, 0xae, 0xa7,
0x52, 0xe2, 0x43, 0xf4, 0x3a, 0x94, 0x36, 0x58, 0x34, 0xf6, 0x9e, 0x0a, 0x27, 0x64, 0x5e, 0xf8,
0x72, 0xe7, 0xd4, 0x72, 0x87, 0x93, 0x67, 0x93, 0x51, 0x87, 0x66, 0x97, 0x06, 0xfb, 0xb8, 0xb8,
0x91, 0xd4, 0x4d, 0x37, 0x01, 0x1d, 0x37, 0xe2, 0x4e, 0x59, 0xdd, 0x22, 0xa7, 0x6c, 0x88, 0x9e,
0x49, 0x66, 0x54, 0x28, 0x8f, 0x47, 0xbe, 0x12, 0x73, 0x55, 0x9a, 0x2f, 0xa4, 0xae, 0x69, 0xc6,
0x4b, 0x90, 0x5d, 0x74, 0x89, 0xd7, 0x46, 0x08, 0x32, 0x89, 0x92, 0x88, 0x71, 0x4c, 0x5f, 0xea,
0x01, 0xf4, 0x19, 0xcf, 0x43, 0x1a, 0xfb, 0xb7, 0xd0, 0x14, 0x0c, 0x79, 0xa4, 0xbb, 0x45, 0xb7,
0x43, 0x36, 0x3d, 0x7d, 0x01, 0xe1, 0x48, 0x44, 0xff, 0x8e, 0x99, 0x94, 0x04, 0x47, 0xdc, 0xdd,
0xd7, 0xa0, 0x20, 0x32, 0xc7, 0x24, 0xec, 0x7b, 0x94, 0x33, 0xbe, 0xc9, 0xc3, 0x90, 0x0b, 0x1c,
0x32, 0x2e, 0x62, 0xc3, 0x0a, 0x43, 0x67, 0xa1, 0x18, 0xf8, 0xb7, 0x42, 0xdb, 0xd9, 0xdc, 0x24,
0x2d, 0x4a, 0x64, 0x87, 0x66, 0xf0, 0x08, 0x57, 0x56, 0x94, 0x0e, 0xfd, 0x07, 0x86, 0xdd, 0x2e,
0x6b, 0x28, 0x6a, 0xbb, 0x6d, 0xd1, 0xa6, 0x19, 0x9c, 0x97, 0x8a, 0x5a, 0x1b, 0xfd, 0x1f, 0x32,
0xdc, 0x78, 0x2a, 0x23, 0xbc, 0x80, 0xf2, 0xc2, 0x72, 0xc0, 0x42, 0x6f, 0xfc, 0xa2, 0xc1, 0xf8,
0x12, 0xa1, 0x0d, 0x12, 0x86, 0xae, 0xdf, 0xad, 0xb5, 0x31, 0x61, 0x16, 0x21, 0x45, 0xaf, 0xc2,
0x38, 0x11, 0x0e, 0xdc, 0x3d, 0x62, 0xb7, 0x44, 0x2b, 0xf3, 0xe5, 0x35, 0xc1, 0xf1, 0xe8, 0xac,
0xdc, 0x64, 0x51, 0x8b, 0xe3, 0xb1, 0xd8, 0x56, 0xa9, 0xda, 0xc8, 0x84, 0x71, 0xb7, 0xd3, 0x21,
0x6d, 0x97, 0x6d, 0x85, 0xc4, 0x02, 0xb2, 0x48, 0x93, 0x51, 0x7f, 0x0d, 0xec, 0x14, 0x3c, 0x16,
0xcf, 0x88, 0x97, 0x49, 0xee, 0xdb, 0xf4, 0x83, 0xf6, 0x6d, 0x26, 0xb1, 0x6f, 0x8d, 0x2b, 0x30,
0x31, 0x98, 0x50, 0xd8, 0xf3, 0x19, 0x1b, 0xe8, 0x7f, 0x00, 0xa1, 0x54, 0x46, 0x89, 0xa4, 0xf1,
0x70, 0x18, 0x99, 0x19, 0x3f, 0xa6, 0xa0, 0x64, 0xde, 0x26, 0xad, 0x3e, 0x25, 0x7f, 0x37, 0x0e,
0x9e, 0x82, 0x1c, 0x15, 0xa7, 0x98, 0x60, 0xa0, 0x50, 0x2e, 0x46, 0x7d, 0x29, 0x94, 0x58, 0x81,
0xe8, 0x69, 0x90, 0x47, 0xa2, 0xa0, 0xa3, 0x50, 0x1e, 0x3b, 0xb6, 0xe9, 0xb0, 0xc4, 0xd9, 0x7a,
0x25, 0x1a, 0x38, 0xdd, 0xd0, 0x61, 0xd1, 0x4a, 0x36, 0xb2, 0x82, 0x8d, 0x62, 0x42, 0xcb, 0xdc,
0x0e, 0x12, 0x96, 0x3b, 0x4a, 0xd8, 0xcb, 0x30, 0x1a, 0xf3, 0xa5, 0x28, 0x9e, 0x81, 0x5c, 0x20,
0xda, 0x5b, 0x71, 0x84, 0x54, 0x08, 0x89, 0xc6, 0xc7, 0xca, 0xc2, 0xf8, 0x2d, 0x05, 0xe3, 0x6a,
0x7e, 0xd5, 0xa1, 0xad, 0xed, 0x47, 0x94, 0xf4, 0x67, 0x61, 0x88, 0xeb, 0x5d, 0x12, 0x6d, 0xb1,
0x13, 0x68, 0x8f, 0x2c, 0x38, 0xf1, 0x4e, 0x68, 0x27, 0x58, 0x16, 0xc4, 0xe7, 0x71, 0xd1, 0x09,
0xad, 0x43, 0xe5, 0x09, 0xf5, 0xc9, 0x9d, 0x5e, 0x9f, 0xa1, 0xa3, 0xf5, 0x59, 0x80, 0x89, 0x41,
0x7e, 0x55, 0x91, 0x2e, 0xc2, 0x90, 0x2c, 0x41, 0x74, 0xf4, 0x9c, 0x54, 0xa5, 0xc8, 0xc4, 0xb8,
0x97, 0x82, 0x89, 0x06, 0x0d, 0x88, 0xd3, 0x79, 0x4c, 0x36, 0xc7, 0x20, 0xab, 0xd9, 0xa3, 0xac,
0xce, 0xc3, 0xe4, 0x11, 0x3a, 0x1e, 0xa2, 0xf7, 0x7f, 0xd5, 0xd8, 0xb5, 0x4d, 0xb6, 0xdc, 0xee,
0x23, 0x4a, 0xe6, 0x20, 0x47, 0x99, 0xa3, 0x1c, 0x5d, 0x85, 0xa2, 0xca, 0x4e, 0x71, 0x73, 0xbc,
0xa1, 0xb5, 0x13, 0x1a, 0xda, 0xb8, 0x93, 0x82, 0xe2, 0xbc, 0xdf, 0xe9, 0xb8, 0xf4, 0x11, 0xe5,
0xe5, 0x78, 0x9e, 0x99, 0xd3, 0x37, 0xee, 0xb1, 0x16, 0xd3, 0xa1, 0x14, 0xb1, 0x20, 0xf9, 0x33,
0xee, 0xa6, 0x60, 0x14, 0xfb, 0x9e, 0xb7, 0xe1, 0xb4, 0x76, 0x1e, 0x6b, 0x6a, 0x10, 0xe8, 0x87,
0x3c, 0x28, 0x72, 0x7e, 0x4e, 0xc1, 0x58, 0xa3, 0xe7, 0xb9, 0x54, 0xed, 0xb4, 0x7f, 0xf6, 0xf1,
0xf4, 0x24, 0x8c, 0x84, 0x3c, 0x59, 0xbb, 0xe5, 0x7b, 0xfd, 0x8e, 0xbc, 0x40, 0x86, 0x71, 0x41,
0xe8, 0xe6, 0x85, 0x8a, 0x7d, 0xc4, 0x16, 0x22, 0x93, 0x7e, 0x97, 0xaa, 0xbb, 0x03, 0x94, 0x05,
0xd3, 0x9c, 0x76, 0x71, 0x60, 0x00, 0xe1, 0x52, 0x90, 0x7a, 0x18, 0x99, 0x76, 0x4a, 0x64, 0xec,
0x33, 0x94, 0x7d, 0x51, 0x2a, 0xa7, 0x29, 0xb1, 0x68, 0x9e, 0x29, 0x84, 0x4b, 0xa3, 0x02, 0x28,
0x59, 0x23, 0x75, 0x2e, 0x24, 0x2e, 0x4f, 0x6d, 0xe0, 0xf2, 0x3c, 0xf4, 0x1f, 0x5f, 0x9e, 0xc6,
0x24, 0x8c, 0xcb, 0x93, 0xf7, 0x3a, 0x71, 0x3c, 0x1a, 0x7d, 0x2f, 0x18, 0x3f, 0xb0, 0x43, 0x03,
0x73, 0x8d, 0xdb, 0x21, 0x0d, 0xea, 0xd0, 0x90, 0x53, 0xb4, 0x2d, 0x4c, 0x6c, 0x12, 0x04, 0x7e,
0xa0, 0x3e, 0xf0, 0x0b, 0x52, 0x67, 0x72, 0x15, 0x2a, 0xc3, 0x64, 0x48, 0x5a, 0x7e, 0xb7, 0x1d,
0xda, 0x1b, 0x64, 0x9b, 0x3f, 0x59, 0x3a, 0x4e, 0x48, 0x49, 0x20, 0xe2, 0x2e, 0xe2, 0x71, 0x05,
0x56, 0x05, 0xb6, 0x22, 0x20, 0x34, 0x07, 0x13, 0xec, 0x81, 0xe2, 0xf9, 0x5b, 0x76, 0xcf, 0x73,
0xf6, 0x49, 0x10, 0xaa, 0x54, 0x79, 0x5d, 0xb3, 0x18, 0x49, 0x6c, 0x4d, 0x42, 0x92, 0xe7, 0x37,
0x61, 0xe6, 0x44, 0x2f, 0xf6, 0xa6, 0xeb, 0xb1, 0x1f, 0xd2, 0xb6, 0x03, 0xc2, 0x72, 0x6c, 0x39,
0xe2, 0x53, 0x40, 0xee, 0x87, 0xf3, 0x27, 0xb8, 0x5e, 0x54, 0xe6, 0xf8, 0xd0, 0x9a, 0xb3, 0xdd,
0xea, 0xf5, 0xed, 0x7e, 0xe8, 0x6c, 0x11, 0xd1, 0x04, 0x1a, 0xce, 0x33, 0x45, 0x93, 0xcb, 0xfc,
0x91, 0xb4, 0xdb, 0x0b, 0x45, 0xe5, 0x35, 0xcc, 0x87, 0xc6, 0xef, 0x5a, 0x74, 0x8d, 0x47, 0xec,
0xc5, 0x47, 0x73, 0xd4, 0x9f, 0xda, 0x5f, 0xf5, 0x27, 0x7b, 0xf0, 0xb0, 0x07, 0xc5, 0x9e, 0xdb,
0xdd, 0x12, 0x14, 0xe5, 0x71, 0x24, 0xa2, 0x06, 0x9c, 0x57, 0xcf, 0x64, 0x72, 0x9b, 0xf2, 0x57,
0xad, 0xe7, 0xed, 0xf3, 0xbc, 0x9c, 0x80, 0x74, 0xd9, 0xeb, 0xc4, 0xe6, 0x75, 0x09, 0xa9, 0xd3,
0xe9, 0x09, 0xa2, 0xd2, 0xf8, 0xac, 0xb4, 0x36, 0x63, 0x63, 0x1c, 0xdb, 0x5a, 0x91, 0x29, 0x7a,
0x11, 0x4a, 0x81, 0xaa, 0xa9, 0x1d, 0xf2, 0xa2, 0xaa, 0x7d, 0x31, 0x11, 0xbd, 0x5f, 0x92, 0x05,
0xc7, 0xc5, 0x20, 0x29, 0xce, 0xec, 0x40, 0x66, 0xd1, 0x73, 0xb6, 0x50, 0x1e, 0x32, 0xf5, 0xd5,
0xba, 0xa9, 0xff, 0x0b, 0x8d, 0x02, 0xd4, 0x1a, 0xb5, 0xba, 0x65, 0x2e, 0xe1, 0xca, 0xb2, 0x7e,
0x90, 0x92, 0x8a, 0x66, 0xbd, 0x51, 0x5b, 0xaa, 0x9b, 0x0b, 0xfa, 0x41, 0x06, 0x8d, 0xc0, 0x50,
0xad, 0xb1, 0xb8, 0xbc, 0x5a, 0xb1, 0xf4, 0x83, 0x3c, 0x2a, 0x42, 0xbe, 0xd6, 0xb8, 0xd1, 0x5c,
0xb5, 0x38, 0xa8, 0xa3, 0x02, 0xe4, 0x6a, 0x0d, 0xcb, 0x7c, 0x83, 0x61, 0x67, 0x24, 0x56, 0xad,
0xd5, 0x2b, 0xf8, 0xa6, 0x7e, 0xf0, 0xda, 0xcc, 0x1f, 0x29, 0xc8, 0xf0, 0xf7, 0x21, 0xd3, 0x0f,
0xd7, 0x9b, 0xcb, 0xcb, 0xb6, 0x75, 0x73, 0x8d, 0xbb, 0x1c, 0x86, 0x0c, 0x73, 0x78, 0x4d, 0x7f,
0x2b, 0x85, 0x00, 0xb2, 0x4d, 0x31, 0x7e, 0x3b, 0xc7, 0xc7, 0x6c, 0xf8, 0xdc, 0x55, 0xfd, 0x9d,
0x14, 0x5f, 0xb6, 0x29, 0x85, 0x3b, 0x11, 0x50, 0xbe, 0xac, 0xbf, 0x1b, 0x03, 0x4c, 0xb8, 0x1b,
0x01, 0x97, 0xca, 0xfa, 0x7b, 0x31, 0xc0, 0x84, 0xf7, 0x23, 0xe0, 0xea, 0x65, 0xfd, 0x83, 0x18,
0x60, 0xc2, 0x87, 0x39, 0x9e, 0x8b, 0xc8, 0x84, 0x99, 0x7d, 0x94, 0x8f, 0x25, 0x86, 0x7d, 0x9c,
0x47, 0x25, 0x18, 0xb6, 0x6a, 0x2b, 0x66, 0xc3, 0xaa, 0xac, 0xac, 0xe9, 0xf7, 0x74, 0x1e, 0xe6,
0x42, 0xc5, 0x32, 0xf5, 0x4f, 0xc4, 0x90, 0x43, 0xfa, 0xa7, 0x3a, 0xcf, 0x91, 0x6b, 0x85, 0xf8,
0x99, 0x40, 0x6e, 0x9a, 0x15, 0xac, 0x7f, 0x9e, 0x63, 0x8e, 0x86, 0x16, 0xcc, 0xf9, 0xda, 0x0a,
0xa3, 0x11, 0x89, 0x19, 0x9c, 0x95, 0x2f, 0xe6, 0xf8, 0xb0, 0xba, 0xbc, 0x5a, 0xd5, 0xbf, 0x5c,
0xe3, 0x0e, 0xd7, 0x2b, 0x78, 0xfe, 0x3a, 0x9b, 0x70, 0x7f, 0x8e, 0x3b, 0x64, 0x92, 0xe2, 0xeb,
0xab, 0x35, 0x6e, 0x28, 0xa0, 0xaf, 0xe7, 0x78, 0xd0, 0x4a, 0xff, 0xcd, 0x1a, 0x2b, 0x56, 0xba,
0x5a, 0xb3, 0xf4, 0x6f, 0x85, 0x37, 0xb3, 0xde, 0x5c, 0xd1, 0xbf, 0xd3, 0xb9, 0xb2, 0x61, 0x5a,
0xfa, 0xf7, 0x5c, 0x99, 0xb5, 0x9a, 0x6b, 0xcb, 0xa6, 0xfe, 0xdf, 0xea, 0x34, 0x4c, 0xb5, 0xfc,
0xce, 0xec, 0xbe, 0xdf, 0xa7, 0xfd, 0x0d, 0x32, 0xbb, 0xe7, 0x52, 0x76, 0x72, 0xc9, 0xff, 0x7b,
0x36, 0x72, 0xe2, 0xe7, 0xd2, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa3, 0x79, 0x25, 0x07, 0x29,
0x12, 0x00, 0x00,
// 1641 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe4, 0x58, 0x49, 0x73, 0xdb, 0xc6,
0x12, 0x7e, 0xe0, 0x26, 0xb2, 0x29, 0x52, 0xd0, 0x50, 0x7a, 0x8f, 0xa5, 0xb7, 0xf9, 0xc1, 0x7e,
0x8e, 0xa3, 0xb8, 0x58, 0x0a, 0xbd, 0xc4, 0x95, 0xd5, 0xa4, 0x04, 0xc9, 0xac, 0x48, 0x14, 0x3d,
0x04, 0x55, 0x71, 0x2e, 0x28, 0x88, 0x1c, 0x51, 0x28, 0x81, 0x04, 0x05, 0x0c, 0x65, 0xeb, 0xa6,
0x24, 0x8e, 0xb3, 0x3a, 0x4b, 0x25, 0xce, 0x7a, 0x4a, 0xe5, 0x9e, 0x1f, 0x91, 0x3f, 0x90, 0x3f,
0x90, 0xca, 0x3d, 0xa7, 0xfc, 0x85, 0xcc, 0x0c, 0x06, 0x20, 0xb5, 0x38, 0xaa, 0xf2, 0x29, 0x8e,
0x4f, 0x9c, 0xee, 0xaf, 0x67, 0x7a, 0xfa, 0xeb, 0x6e, 0xcc, 0x0c, 0x21, 0xbb, 0x3b, 0x24, 0xde,
0x7e, 0x69, 0xe0, 0xb9, 0xd4, 0x45, 0x49, 0x21, 0xcc, 0xe5, 0xa9, 0x3b, 0x70, 0x3b, 0x16, 0xb5,
0x02, 0xf5, 0x5c, 0x76, 0x8f, 0x7a, 0x83, 0x76, 0x20, 0x68, 0xbb, 0x90, 0x32, 0x2c, 0xaf, 0x4b,
0x28, 0x9a, 0x83, 0xf4, 0x0e, 0xd9, 0xf7, 0x07, 0x56, 0x9b, 0x14, 0x95, 0x33, 0xca, 0x85, 0x0c,
0x8e, 0x64, 0x34, 0x03, 0x49, 0x7f, 0xdb, 0xf2, 0x3a, 0xc5, 0x98, 0x00, 0x02, 0x01, 0x5d, 0x81,
0x2c, 0xb5, 0x36, 0x1d, 0x42, 0x4d, 0xba, 0x3f, 0x20, 0xc5, 0x38, 0xc3, 0xf2, 0xe5, 0x99, 0x52,
0xe4, 0xce, 0x10, 0xa0, 0xc1, 0x30, 0x0c, 0x34, 0x1a, 0x6b, 0x17, 0x21, 0xbf, 0x61, 0xac, 0x58,
0x94, 0x2c, 0x5a, 0x8e, 0x43, 0xbc, 0xda, 0x12, 0x77, 0x3d, 0xf4, 0x89, 0xd7, 0xb7, 0x7a, 0x91,
0xeb, 0x50, 0xd6, 0x5e, 0x86, 0xe4, 0x86, 0xe5, 0x0c, 0x09, 0xfa, 0x2f, 0x24, 0x84, 0x1b, 0x45,
0xb8, 0xc9, 0x96, 0x82, 0x48, 0xc5, 0xea, 0x02, 0xe0, 0x9b, 0xdc, 0xe3, 0x96, 0x62, 0x93, 0x93,
0x38, 0x10, 0xb4, 0x1d, 0x98, 0xac, 0xda, 0xfd, 0xce, 0x86, 0xe5, 0xd9, 0x7c, 0x0b, 0x8f, 0xb8,
0x0c, 0x3a, 0x07, 0x29, 0x31, 0xf0, 0x59, 0x98, 0xf1, 0x0b, 0xd9, 0xf2, 0xa4, 0x9c, 0x28, 0xf6,
0x86, 0x25, 0xa6, 0xfd, 0xa8, 0x00, 0x54, 0xdd, 0x61, 0xbf, 0x73, 0x93, 0x83, 0x48, 0x85, 0xb8,
0xbf, 0xeb, 0xc8, 0x90, 0xf8, 0x10, 0xbd, 0x0a, 0xf9, 0x4d, 0xb6, 0x1b, 0x73, 0x4f, 0x6e, 0xc7,
0x67, 0x5e, 0xf8, 0x72, 0xe7, 0xe4, 0x72, 0xa3, 0xc9, 0xa5, 0xf1, 0x5d, 0xfb, 0x7a, 0x9f, 0x7a,
0xfb, 0x38, 0xb7, 0x39, 0xae, 0x9b, 0x6b, 0x01, 0x3a, 0x6e, 0xc4, 0x9d, 0xb2, 0xbc, 0x85, 0x4e,
0xd9, 0x10, 0x3d, 0x3d, 0x1e, 0x51, 0xb6, 0x5c, 0x08, 0x7d, 0x8d, 0xcd, 0x95, 0x61, 0x3e, 0x1f,
0xbb, 0xa6, 0x68, 0x2f, 0x42, 0x72, 0xd9, 0x26, 0x4e, 0x07, 0x21, 0x48, 0x8c, 0xa5, 0x44, 0x8c,
0x23, 0xfa, 0x62, 0x0f, 0xa1, 0x4f, 0x7b, 0x0e, 0xe2, 0xd8, 0xbd, 0x8d, 0x8a, 0x30, 0xe1, 0x90,
0x7e, 0x97, 0x6e, 0xfb, 0x6c, 0x7a, 0xfc, 0x02, 0xc2, 0xa1, 0x88, 0xfe, 0x1e, 0x31, 0x19, 0x10,
0x1c, 0x72, 0xf7, 0x40, 0x81, 0xac, 0x88, 0x1c, 0x13, 0x7f, 0xe8, 0x50, 0xce, 0xf8, 0x16, 0xdf,
0x46, 0xb0, 0xc0, 0x88, 0x71, 0xb1, 0x37, 0x2c, 0x31, 0x74, 0x16, 0x72, 0x9e, 0x7b, 0xdb, 0x37,
0xad, 0xad, 0x2d, 0xd2, 0xa6, 0x24, 0xa8, 0xd0, 0x04, 0x9e, 0xe4, 0xca, 0x8a, 0xd4, 0xa1, 0x7f,
0x42, 0xc6, 0xee, 0xb3, 0x82, 0xa2, 0xa6, 0xdd, 0x11, 0x65, 0x9a, 0xc0, 0xe9, 0x40, 0x51, 0xeb,
0xa0, 0xff, 0x40, 0x82, 0x1b, 0x17, 0x13, 0xc2, 0x0b, 0x48, 0x2f, 0x2c, 0x06, 0x2c, 0xf4, 0xda,
0x4f, 0x0a, 0x14, 0x56, 0x08, 0x6d, 0x12, 0xdf, 0xb7, 0xdd, 0x7e, 0xad, 0x83, 0x09, 0xb3, 0xf0,
0x29, 0x7a, 0x05, 0x0a, 0x44, 0x38, 0xb0, 0xf7, 0x88, 0xd9, 0x16, 0xa5, 0xcc, 0x97, 0x57, 0x04,
0xc7, 0x53, 0xa5, 0xa0, 0xc9, 0xc2, 0x12, 0xc7, 0xd3, 0x91, 0xad, 0x54, 0x75, 0x90, 0x0e, 0x05,
0xbb, 0xd7, 0x23, 0x1d, 0x9b, 0xb5, 0xc2, 0xd8, 0x02, 0x41, 0x92, 0x66, 0xc3, 0xfa, 0x3a, 0xd4,
0x29, 0x78, 0x3a, 0x9a, 0x11, 0x2d, 0x33, 0xde, 0xb7, 0xf1, 0x87, 0xf5, 0x6d, 0x62, 0xac, 0x6f,
0xb5, 0x2b, 0x30, 0x73, 0x38, 0x20, 0x7f, 0xe0, 0x32, 0x36, 0xd0, 0xbf, 0x01, 0xfc, 0x40, 0x19,
0x06, 0x12, 0xc7, 0x19, 0x3f, 0x34, 0xd3, 0x7e, 0x88, 0x41, 0x5e, 0xbf, 0x43, 0xda, 0x43, 0x4a,
0xfe, 0x6c, 0x1c, 0xfc, 0x1f, 0x52, 0x54, 0x7c, 0xc5, 0x04, 0x03, 0xd9, 0x72, 0x2e, 0xac, 0x4b,
0xa1, 0xc4, 0x12, 0x44, 0x4f, 0x41, 0xf0, 0x49, 0x14, 0x74, 0x64, 0xcb, 0xd3, 0xc7, 0x9a, 0x0e,
0x07, 0x38, 0x5b, 0x2f, 0x4f, 0x3d, 0xab, 0xef, 0x5b, 0x6c, 0xb7, 0x01, 0x1b, 0x49, 0xc1, 0x46,
0x6e, 0x4c, 0xcb, 0xdc, 0x1e, 0x26, 0x2c, 0x75, 0x94, 0xb0, 0x97, 0x60, 0x2a, 0xe2, 0x4b, 0x52,
0x3c, 0x0f, 0x29, 0x4f, 0x94, 0xb7, 0xe4, 0x08, 0xc9, 0x2d, 0x8c, 0x15, 0x3e, 0x96, 0x16, 0xda,
0x2f, 0x31, 0x28, 0xc8, 0xf9, 0x55, 0x8b, 0xb6, 0xb7, 0x1f, 0x53, 0xd2, 0x9f, 0x81, 0x09, 0xae,
0xb7, 0x49, 0xd8, 0x62, 0x27, 0xd0, 0x1e, 0x5a, 0x70, 0xe2, 0x2d, 0xdf, 0x1c, 0x63, 0x59, 0x10,
0x9f, 0xc6, 0x39, 0xcb, 0x37, 0x46, 0xca, 0x13, 0xf2, 0x93, 0x3a, 0x3d, 0x3f, 0x13, 0x47, 0xf3,
0xb3, 0x04, 0x33, 0x87, 0xf9, 0x95, 0x49, 0xba, 0x08, 0x13, 0x41, 0x0a, 0xc2, 0x4f, 0xcf, 0x49,
0x59, 0x0a, 0x4d, 0xb4, 0xfb, 0x31, 0x98, 0x69, 0x52, 0x8f, 0x58, 0xbd, 0x27, 0xa4, 0x39, 0x0e,
0xb3, 0x9a, 0x3c, 0xca, 0xea, 0x22, 0xcc, 0x1e, 0xa1, 0xe3, 0x11, 0x6a, 0xff, 0x67, 0x85, 0x1d,
0xdb, 0xa4, 0x6b, 0xf7, 0x1f, 0x53, 0x32, 0x0f, 0x73, 0x94, 0x38, 0xca, 0xd1, 0x55, 0xc8, 0xc9,
0xe8, 0x24, 0x37, 0xc7, 0x0b, 0x5a, 0x39, 0xa1, 0xa0, 0xb5, 0xbb, 0x31, 0xc8, 0x2d, 0xba, 0xbd,
0x9e, 0x4d, 0x1f, 0x53, 0x5e, 0x8e, 0xc7, 0x99, 0x38, 0xbd, 0x71, 0x8f, 0x95, 0x98, 0x0a, 0xf9,
0x90, 0x85, 0x80, 0x3f, 0xed, 0x5e, 0x0c, 0xa6, 0xb0, 0xeb, 0x38, 0x9b, 0x56, 0x7b, 0xe7, 0x89,
0xa6, 0x06, 0x81, 0x3a, 0xe2, 0x41, 0x92, 0xf3, 0x5d, 0x02, 0xa6, 0x9b, 0x03, 0xc7, 0xa6, 0xb2,
0xd3, 0xfe, 0xda, 0x9f, 0xa7, 0xff, 0xc1, 0xa4, 0xcf, 0x83, 0x35, 0xdb, 0xae, 0x33, 0xec, 0xf1,
0x03, 0x24, 0xce, 0xae, 0x3e, 0x59, 0xa1, 0x5b, 0x14, 0x2a, 0x76, 0x89, 0xcd, 0x86, 0x26, 0xc3,
0x3e, 0x95, 0x67, 0x07, 0x48, 0x0b, 0xa6, 0x41, 0x97, 0xe1, 0x1f, 0xfd, 0x61, 0xcf, 0x14, 0x37,
0xcb, 0x01, 0x0b, 0x4b, 0xac, 0x6c, 0x0e, 0x2c, 0x8f, 0x16, 0xd3, 0xc2, 0xb8, 0xc0, 0x60, 0x76,
0x45, 0xf4, 0x1b, 0xc4, 0x13, 0xce, 0x1b, 0x0c, 0x3a, 0xe5, 0xb8, 0x41, 0xd7, 0x21, 0x63, 0x39,
0x5d, 0xd7, 0xb3, 0xe9, 0x76, 0xaf, 0x98, 0x11, 0xf7, 0x67, 0x4d, 0x46, 0x71, 0x2c, 0x3b, 0xa5,
0x4a, 0x68, 0x89, 0x47, 0x93, 0xd8, 0x51, 0x8a, 0xd8, 0xbb, 0xc8, 0x0c, 0xf6, 0x1e, 0xec, 0x69,
0xaf, 0x5c, 0x04, 0x71, 0x42, 0x4e, 0x31, 0x64, 0xb4, 0xcc, 0x46, 0x99, 0x3d, 0xb3, 0x32, 0xd1,
0x22, 0xec, 0x51, 0x30, 0xa9, 0xdf, 0x6c, 0x55, 0x56, 0xcd, 0x66, 0x63, 0xb5, 0x66, 0x34, 0xd5,
0xbf, 0xa1, 0x1c, 0x64, 0x96, 0x5b, 0xab, 0x4c, 0xb1, 0x58, 0xa9, 0xab, 0x8a, 0x86, 0x01, 0xc4,
0x44, 0xb1, 0xc4, 0x88, 0x6c, 0xe5, 0x14, 0xb2, 0xd9, 0xcd, 0x9a, 0x91, 0x24, 0x79, 0x8c, 0x89,
0x88, 0xd3, 0x4c, 0x21, 0x58, 0xd4, 0x2a, 0x80, 0xc6, 0x03, 0x93, 0x9f, 0xba, 0xb1, 0xfb, 0x80,
0x72, 0xe8, 0x3e, 0x30, 0xf2, 0x1f, 0xdd, 0x07, 0xb4, 0x59, 0x28, 0x04, 0x87, 0xc9, 0x0d, 0x62,
0x39, 0x34, 0xbc, 0x02, 0x69, 0xdf, 0xb3, 0xef, 0x20, 0xe6, 0x1a, 0xbb, 0x47, 0x9a, 0xd4, 0xa2,
0x3e, 0xcf, 0xfa, 0xb6, 0x30, 0x31, 0x89, 0xe7, 0xb9, 0x9e, 0x7c, 0xb3, 0x64, 0x03, 0x9d, 0xce,
0x55, 0xa8, 0x0c, 0xb3, 0x3e, 0x69, 0xbb, 0xfd, 0x8e, 0x6f, 0x6e, 0x92, 0x6d, 0xfe, 0x0a, 0xeb,
0x59, 0x3e, 0x25, 0x9e, 0xd8, 0x77, 0x0e, 0x17, 0x24, 0x58, 0x15, 0xd8, 0x9a, 0x80, 0xd0, 0x02,
0xcc, 0xb0, 0x37, 0x97, 0xe3, 0x76, 0xcd, 0x81, 0x63, 0xed, 0x13, 0xcf, 0x97, 0xa1, 0xf2, 0x52,
0x4d, 0x62, 0x14, 0x60, 0x8d, 0x00, 0x0a, 0x4a, 0xe7, 0x75, 0x98, 0x3f, 0xd1, 0x8b, 0xb9, 0x65,
0x3b, 0xec, 0x87, 0x74, 0x4c, 0x8f, 0xb0, 0x18, 0xdb, 0x96, 0xb8, 0xdd, 0x04, 0x2d, 0x7e, 0xfe,
0x04, 0xd7, 0xcb, 0xd2, 0x1c, 0x8f, 0xac, 0x39, 0xdb, 0xed, 0xc1, 0xd0, 0x1c, 0xfa, 0x56, 0x97,
0x88, 0xd6, 0x57, 0x70, 0x9a, 0x29, 0x5a, 0x5c, 0xe6, 0xef, 0xbe, 0xdd, 0x81, 0x2f, 0x8a, 0x59,
0xc1, 0x7c, 0xa8, 0xfd, 0xaa, 0x84, 0x37, 0x93, 0x90, 0xbd, 0xe8, 0xb4, 0x09, 0x5b, 0x4e, 0xf9,
0xa3, 0x96, 0x63, 0x6f, 0x38, 0xf6, 0x46, 0xda, 0xb3, 0xfb, 0x5d, 0x41, 0x51, 0x1a, 0x87, 0x22,
0x6a, 0xc2, 0x79, 0xf9, 0xf2, 0x27, 0x77, 0x28, 0x7f, 0xa8, 0x3b, 0xce, 0x3e, 0x8f, 0xcb, 0xf2,
0x48, 0x9f, 0x3d, 0xb8, 0x4c, 0x9e, 0x17, 0x9f, 0x5a, 0xbd, 0x81, 0x20, 0x2a, 0x8e, 0xcf, 0x06,
0xd6, 0x7a, 0x64, 0x8c, 0x23, 0x5b, 0x23, 0x34, 0x45, 0x2f, 0x40, 0xde, 0x93, 0x39, 0x35, 0x7d,
0x9e, 0x54, 0xd9, 0xea, 0x33, 0xe1, 0x93, 0x6c, 0x3c, 0xe1, 0x38, 0xe7, 0x8d, 0x8b, 0xf3, 0x3b,
0x90, 0x58, 0x76, 0xac, 0x2e, 0x4a, 0x43, 0xa2, 0xbe, 0x5e, 0xd7, 0x59, 0x81, 0x4f, 0x01, 0xd4,
0x9a, 0xb5, 0xba, 0xa1, 0xaf, 0xe0, 0xca, 0xaa, 0x7a, 0x10, 0x0b, 0x14, 0xad, 0x7a, 0xb3, 0xb6,
0x52, 0xd7, 0x97, 0xd4, 0x83, 0x04, 0x9a, 0x84, 0x89, 0x5a, 0x73, 0x79, 0x75, 0xbd, 0x62, 0xa8,
0x07, 0x69, 0xd6, 0x10, 0xe9, 0x5a, 0xf3, 0x66, 0x6b, 0xdd, 0xe0, 0xa0, 0x8a, 0xb2, 0x90, 0xaa,
0x35, 0x0d, 0xfd, 0x35, 0x86, 0x9d, 0x09, 0xb0, 0x6a, 0xad, 0x5e, 0xc1, 0xb7, 0xd4, 0x83, 0xeb,
0xf3, 0xbf, 0xc5, 0x20, 0xc1, 0x9f, 0xbc, 0xbc, 0x89, 0xea, 0xbc, 0x89, 0x8c, 0x5b, 0x0d, 0xee,
0x32, 0x03, 0x09, 0xe6, 0xf0, 0x9a, 0xfa, 0x46, 0x0c, 0x01, 0x24, 0x5b, 0x62, 0xfc, 0x66, 0x8a,
0x8f, 0xd9, 0xf0, 0xd9, 0xab, 0xea, 0x5b, 0x31, 0xbe, 0x6c, 0x2b, 0x10, 0xee, 0x86, 0x40, 0xf9,
0xb2, 0xfa, 0x76, 0x04, 0x30, 0xe1, 0x5e, 0x08, 0x5c, 0x2a, 0xab, 0xef, 0x44, 0x00, 0x13, 0xde,
0x0d, 0x81, 0xab, 0x97, 0xd5, 0xf7, 0x22, 0x80, 0x09, 0xef, 0xa7, 0x78, 0x2c, 0x22, 0x12, 0x66,
0xf6, 0x41, 0x3a, 0x92, 0x18, 0xf6, 0x61, 0x1a, 0xe5, 0x21, 0x63, 0xd4, 0xd6, 0xf4, 0xa6, 0x51,
0x59, 0x6b, 0xa8, 0xf7, 0x55, 0xbe, 0xcd, 0xa5, 0x8a, 0xa1, 0xab, 0x1f, 0x89, 0x21, 0x87, 0xd4,
0x8f, 0x55, 0x1e, 0x23, 0xd7, 0x0a, 0xf1, 0x13, 0x81, 0xdc, 0xd2, 0x2b, 0x58, 0xfd, 0x34, 0xc5,
0x1c, 0x4d, 0x2c, 0xe9, 0x8b, 0xb5, 0x35, 0x46, 0x23, 0x12, 0x33, 0x38, 0x2b, 0x9f, 0x2d, 0xf0,
0x61, 0x75, 0x75, 0xbd, 0xaa, 0x7e, 0xde, 0xe0, 0x0e, 0x37, 0x2a, 0x78, 0xf1, 0x06, 0x9b, 0xf0,
0x60, 0x81, 0x3b, 0x64, 0x92, 0xe4, 0xeb, 0x8b, 0x06, 0x37, 0x14, 0xd0, 0x97, 0x0b, 0x7c, 0xd3,
0x52, 0xff, 0x55, 0x83, 0x25, 0x2b, 0x5e, 0xad, 0x19, 0xea, 0xd7, 0xc2, 0x9b, 0x5e, 0x6f, 0xad,
0xa9, 0xdf, 0xa8, 0x5c, 0xd9, 0xd4, 0x0d, 0xf5, 0x5b, 0xae, 0x4c, 0x1a, 0xad, 0xc6, 0xaa, 0xae,
0xfe, 0xab, 0x3a, 0x07, 0xc5, 0xb6, 0xdb, 0x2b, 0xed, 0xbb, 0x43, 0x3a, 0xdc, 0x24, 0xa5, 0x3d,
0x9b, 0xb2, 0xcf, 0x6a, 0xf0, 0x17, 0xd6, 0x66, 0x4a, 0xfc, 0x5c, 0xfa, 0x3d, 0x00, 0x00, 0xff,
0xff, 0xa4, 0xf3, 0x84, 0xc5, 0xfc, 0x12, 0x00, 0x00,
}

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

@ -114,6 +114,8 @@ type ExecuteRequest struct {
TabletType topodata.TabletType `protobuf:"varint,4,opt,name=tablet_type,json=tabletType,enum=topodata.TabletType" json:"tablet_type,omitempty"`
// not_in_transaction is deprecated and should not be used.
NotInTransaction bool `protobuf:"varint,5,opt,name=not_in_transaction,json=notInTransaction" json:"not_in_transaction,omitempty"`
// keyspace to target the query to.
Keyspace string `protobuf:"bytes,6,opt,name=keyspace" json:"keyspace,omitempty"`
}
func (m *ExecuteRequest) Reset() { *m = ExecuteRequest{} }
@ -774,6 +776,8 @@ type StreamExecuteRequest struct {
Query *query.BoundQuery `protobuf:"bytes,2,opt,name=query" json:"query,omitempty"`
// tablet_type is the type of tablets that this query is targeted to.
TabletType topodata.TabletType `protobuf:"varint,3,opt,name=tablet_type,json=tabletType,enum=topodata.TabletType" json:"tablet_type,omitempty"`
// keyspace to target the query to.
Keyspace string `protobuf:"bytes,4,opt,name=keyspace" json:"keyspace,omitempty"`
}
func (m *StreamExecuteRequest) Reset() { *m = StreamExecuteRequest{} }
@ -1102,18 +1106,95 @@ func (*RollbackResponse) ProtoMessage() {}
func (*RollbackResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} }
// SplitQueryRequest is the payload to SplitQuery.
//
// SplitQuery takes a "SELECT" query and generates a list of queries called
// "query-parts". Each query-part consists of the original query with an
// added WHERE clause that restricts the query-part to operate only on
// rows whose values in the the columns listed in the "split_column" field
// of the request (see below) are in a particular range.
//
// It is guaranteed that the set of rows obtained from
// executing each query-part on a database snapshot
// and merging (without deduping) the results is equal to the set of rows
// obtained from executing the original query on the same snapshot
// with the rows containing NULL values in any of the split_column's excluded.
//
// This is typically called by the MapReduce master when reading from Vitess.
// There it's desirable that the sets of rows returned by the query-parts
// have roughly the same size.
type SplitQueryRequest struct {
// caller_id identifies the caller. This is the effective caller ID,
// set by the application to further identify the caller.
CallerId *vtrpc.CallerID `protobuf:"bytes,1,opt,name=caller_id,json=callerId" json:"caller_id,omitempty"`
// keyspace to target the query to.
Keyspace string `protobuf:"bytes,2,opt,name=keyspace" json:"keyspace,omitempty"`
// query is the query and bind variables to produce splits for.
// The query and bind variables to produce splits for.
// The given query must be a simple query of the form
// SELECT <cols> FROM <table> WHERE <filter>.
// It must not contain subqueries nor any of the keywords
// JOIN, GROUP BY, ORDER BY, LIMIT, DISTINCT.
// Furthermore, <table> must be a single “concrete” table.
// It cannot be a view.
Query *query.BoundQuery `protobuf:"bytes,3,opt,name=query" json:"query,omitempty"`
// split_column is an optional hint on the column to use to split the query.
SplitColumn string `protobuf:"bytes,4,opt,name=split_column,json=splitColumn" json:"split_column,omitempty"`
// split_count describes how many splits we want for this query.
SplitCount int64 `protobuf:"varint,5,opt,name=split_count,json=splitCount" json:"split_count,omitempty"`
// Each generated query-part will be restricted to rows whose values
// in the columns listed in this field are in a particular range.
// The list of columns named here must be a prefix of the list of
// columns defining some index or primary key of the table
// referenced in 'query'. For many tables using the primary key columns
// (in order) is sufficient and this is the default if this field is omitted.
// See the comment on the 'algorithm' field for more restrictions and
// information.
SplitColumn []string `protobuf:"bytes,4,rep,name=split_column,json=splitColumn" json:"split_column,omitempty"`
// You can specify either an estimate of the number of query-parts to
// generate or an estimate of the number of rows each query-part should
// return.
// Thus, exactly one of split_count or num_rows_per_query_part
// should be nonzero.
// The non-given parameter is calculated from the given parameter
// using the formula: split_count * num_rows_per_query_pary = table_size,
// where table_size is an approximation of the number of rows in the
// table.
// Note that if "split_count" is given it is regarded as an estimate.
// The number of query-parts returned may differ slightly (in particular,
// if it's not a whole multiple of the number of vitess shards).
SplitCount int64 `protobuf:"varint,5,opt,name=split_count,json=splitCount" json:"split_count,omitempty"`
NumRowsPerQueryPart int64 `protobuf:"varint,6,opt,name=num_rows_per_query_part,json=numRowsPerQueryPart" json:"num_rows_per_query_part,omitempty"`
// The algorithm to use to split the query. The split algorithm is performed
// on each database shard in parallel. The lists of query-parts generated
// by the shards are merged and returned to the caller.
// Two algorithms are supported:
// EQUAL_SPLITS
// If this algorithm is used then only one split_column is allowed.
// Additionally, the split_column must have numeric type (integral or
// floating point). The algorithm works by taking the interval [min, max],
// where min and max are the minimum and maximum values of of the
// split_column column in the table-shard, respectively, and
// partitioning it into split_count sub-intervals of equal size.
// The added WHERE clause of each query-part restricts that part to rows
// whose value in split_column belongs to a particular sub-interval.
// This is fast, but requires that the distribution of values of
// split_column be uniform in [min, max], for the number of rows
// returned by each query part to be roughly the same.
// FULL_SCAN
// If this algorithm is used then the split_column must be the primary key
// columns (in order).
// This algorithm performs a full-scan of the table-shard referenced
// in 'query' to get "boundary" rows that are num_rows_per_query_part
// apart when the table is ordered by the columns listed in
// 'split_column'. It then restricts each query-part to the rows
// located between two successive boundary rows.
// This algorithm supports multiple split_column's of any type,
// but is slower than EQUAL_SPLITS.
Algorithm query.SplitQueryRequest_Algorithm `protobuf:"varint,7,opt,name=algorithm,enum=query.SplitQueryRequest_Algorithm" json:"algorithm,omitempty"`
// Whether to use the new split-query code
// that supports multiple split-columns and
// the FULL_SCAN algorithm.
// This is a temporary field which aids
// in the migration of SplitQuery to the new
// code.
// TODO(erez): Remove this field after the migration
// to the SplitQuery version 2.
UseSplitQueryV2 bool `protobuf:"varint,8,opt,name=use_split_query_v2,json=useSplitQueryV2" json:"use_split_query_v2,omitempty"`
}
func (m *SplitQueryRequest) Reset() { *m = SplitQueryRequest{} }
@ -1191,7 +1272,8 @@ func (*SplitQueryResponse_ShardPart) Descriptor() ([]byte, []int) {
type SplitQueryResponse_Part struct {
// query is the query and bind variables to execute.
Query *query.BoundQuery `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"`
// key_range_part is set if the query should be executed by ExecuteKeyRanges.
// key_range_part is set if the query should be executed by
// ExecuteKeyRanges.
KeyRangePart *SplitQueryResponse_KeyRangePart `protobuf:"bytes,2,opt,name=key_range_part,json=keyRangePart" json:"key_range_part,omitempty"`
// shard_part is set if the query should be executed by ExecuteShards.
ShardPart *SplitQueryResponse_ShardPart `protobuf:"bytes,3,opt,name=shard_part,json=shardPart" json:"shard_part,omitempty"`
@ -1298,82 +1380,88 @@ func init() {
}
var fileDescriptor0 = []byte{
// 1230 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xd4, 0x59, 0xcf, 0x6f, 0xe3, 0xc4,
0x17, 0x97, 0xe3, 0x34, 0x69, 0x9e, 0x93, 0xb4, 0xf5, 0xb7, 0xdd, 0xcd, 0xd7, 0x2c, 0xdb, 0x62,
0x81, 0xb6, 0xa0, 0x95, 0xa5, 0xed, 0x8a, 0x1f, 0x42, 0x48, 0x48, 0x0d, 0x15, 0x8a, 0x16, 0x56,
0xcb, 0xb4, 0x07, 0x0e, 0x20, 0xcb, 0x4d, 0x46, 0xad, 0x49, 0x62, 0x07, 0xcf, 0x24, 0x22, 0x1c,
0xb8, 0x21, 0x71, 0xdb, 0x13, 0x12, 0x42, 0x5c, 0x90, 0xf8, 0x07, 0xf8, 0x13, 0x38, 0x21, 0x71,
0xe1, 0xc0, 0x81, 0x1b, 0x7f, 0x02, 0x57, 0x2e, 0x1c, 0x18, 0xcf, 0x8c, 0x7f, 0xc4, 0x4d, 0xd2,
0x34, 0x69, 0xa3, 0xf4, 0x54, 0xcf, 0xcc, 0x9b, 0x79, 0xef, 0x7d, 0x3e, 0x9f, 0x79, 0x33, 0xd3,
0x40, 0x79, 0x40, 0xcf, 0x1c, 0x8a, 0xad, 0x5e, 0xe0, 0x53, 0x5f, 0x2f, 0x88, 0x96, 0xa1, 0x7d,
0xde, 0xc7, 0xc1, 0x50, 0x74, 0x1a, 0x55, 0xea, 0xf7, 0xfc, 0x96, 0x43, 0x1d, 0xd9, 0xd6, 0x06,
0x34, 0xe8, 0x35, 0x45, 0xc3, 0xfc, 0x43, 0x81, 0xe2, 0x31, 0x26, 0xc4, 0xf5, 0x3d, 0xfd, 0x15,
0xa8, 0xba, 0x9e, 0x4d, 0x03, 0xc7, 0x23, 0x4e, 0x93, 0xb2, 0x9e, 0x9a, 0xb2, 0xa7, 0xec, 0xaf,
0xa3, 0x8a, 0xeb, 0x9d, 0x24, 0x9d, 0x7a, 0x1d, 0xaa, 0xe4, 0xdc, 0x09, 0x5a, 0x36, 0x11, 0xf3,
0x48, 0x2d, 0xb7, 0xa7, 0xee, 0x6b, 0x07, 0xf7, 0x2c, 0x19, 0x8b, 0x5c, 0xcf, 0x3a, 0x0e, 0xad,
0x64, 0x03, 0x55, 0x48, 0xaa, 0x45, 0x8c, 0x4f, 0xa0, 0x9c, 0x1e, 0x66, 0xbe, 0x0b, 0xd4, 0x09,
0xce, 0x30, 0xe5, 0x3e, 0xb5, 0x83, 0x8a, 0x25, 0x52, 0x38, 0xe1, 0x9d, 0x48, 0x0e, 0x86, 0x21,
0xa6, 0xe2, 0xb3, 0xdd, 0x16, 0xf3, 0xad, 0xec, 0xab, 0xa8, 0x92, 0xea, 0x6d, 0xb4, 0xcc, 0x7f,
0x14, 0xa8, 0x1e, 0x7d, 0x81, 0x9b, 0x7d, 0x8a, 0x11, 0x66, 0x0b, 0x11, 0xaa, 0x3f, 0x84, 0x52,
0xd3, 0xe9, 0x74, 0x70, 0x10, 0x4e, 0x12, 0x3e, 0x36, 0x2c, 0x81, 0x44, 0x9d, 0xf7, 0x37, 0xde,
0x43, 0xeb, 0xc2, 0xa2, 0xd1, 0xd2, 0x5f, 0x85, 0xa2, 0xcc, 0x8e, 0x3b, 0x10, 0xb6, 0xe9, 0xe4,
0x50, 0x34, 0xae, 0x3f, 0x80, 0x35, 0x1e, 0x6a, 0x4d, 0xe5, 0x86, 0x5b, 0x32, 0xf0, 0x43, 0xbf,
0xef, 0xb5, 0x3e, 0x0a, 0x3f, 0x91, 0x18, 0xd7, 0x5f, 0x07, 0x8d, 0x3a, 0xa7, 0x1d, 0x4c, 0x6d,
0x3a, 0xec, 0xe1, 0x5a, 0x9e, 0x99, 0x57, 0x0f, 0xb6, 0xad, 0x98, 0x9d, 0x13, 0x3e, 0x78, 0xc2,
0xc6, 0x10, 0xd0, 0xf8, 0x9b, 0x05, 0xae, 0x7b, 0x3e, 0xb5, 0x33, 0xcc, 0xac, 0x71, 0x66, 0x36,
0xd9, 0x48, 0x23, 0x4d, 0x8e, 0xf9, 0x5c, 0x81, 0x8d, 0x38, 0x73, 0xd2, 0x63, 0x50, 0x63, 0x06,
0xda, 0x1a, 0x0e, 0x02, 0x3f, 0xc8, 0xa4, 0x8d, 0x9e, 0xd5, 0x8f, 0xc2, 0x6e, 0x24, 0x46, 0xaf,
0x92, 0xf3, 0x6b, 0x50, 0x08, 0x30, 0xe9, 0x77, 0xa8, 0x4c, 0x5a, 0x97, 0x49, 0x8b, 0x7c, 0xf9,
0x08, 0x92, 0x16, 0xe6, 0xcf, 0x39, 0xd8, 0x96, 0x11, 0x71, 0xc6, 0xc9, 0xea, 0x30, 0x62, 0xc0,
0x7a, 0x1b, 0x0f, 0x49, 0xcf, 0x69, 0x0a, 0x3a, 0x4a, 0x28, 0x6e, 0xeb, 0x77, 0xa0, 0xc0, 0x15,
0x4b, 0x18, 0xd4, 0x2a, 0x1b, 0x91, 0xad, 0x2c, 0x8b, 0x85, 0x85, 0x58, 0x2c, 0x4e, 0x60, 0xf1,
0x5b, 0x05, 0x76, 0x32, 0x98, 0xad, 0x04, 0x97, 0xbf, 0xe4, 0xe0, 0xff, 0x32, 0xae, 0x27, 0x12,
0xa8, 0xc6, 0x6d, 0x21, 0xf4, 0x25, 0x28, 0x47, 0xdf, 0x2c, 0x3e, 0x41, 0x6b, 0x19, 0x69, 0xed,
0x24, 0x8f, 0xe5, 0x70, 0xfb, 0xbd, 0x02, 0xc6, 0x38, 0x0c, 0x57, 0x82, 0xe0, 0xdf, 0x73, 0x70,
0x37, 0x09, 0x0e, 0x39, 0xde, 0x19, 0xbe, 0x25, 0xf4, 0x3e, 0x02, 0x60, 0xdf, 0x76, 0xc0, 0x43,
0xe6, 0xe4, 0x86, 0x99, 0xc6, 0xd4, 0x45, 0xd9, 0xa0, 0x52, 0x3b, 0xca, 0x6b, 0x39, 0x74, 0x7f,
0xa7, 0x40, 0xed, 0x22, 0xa2, 0x2b, 0x41, 0xf6, 0x37, 0xf9, 0x98, 0xec, 0x23, 0x8f, 0xba, 0x74,
0x78, 0x6b, 0xf6, 0x32, 0xa3, 0x00, 0xf3, 0x88, 0xed, 0xa6, 0xdf, 0xe9, 0x77, 0x3d, 0xdb, 0x73,
0xba, 0x98, 0x9f, 0x89, 0x25, 0xb4, 0x29, 0x46, 0xea, 0x7c, 0xe0, 0x29, 0xeb, 0xd7, 0x3f, 0x86,
0xff, 0x49, 0xeb, 0x91, 0x02, 0x50, 0xe0, 0x1a, 0xd9, 0x8f, 0x22, 0x9d, 0x80, 0x84, 0x15, 0x75,
0xa0, 0x2d, 0xb1, 0xc8, 0x93, 0xc9, 0x05, 0xa3, 0xb8, 0x90, 0x82, 0xd6, 0xc7, 0x2b, 0xc8, 0x38,
0x85, 0xf5, 0x28, 0x06, 0x7d, 0x17, 0xf2, 0xdc, 0x93, 0xc2, 0x3d, 0x69, 0xd1, 0x25, 0x29, 0x74,
0xc0, 0x07, 0xf4, 0x6d, 0x58, 0x1b, 0x38, 0x9d, 0x3e, 0xe6, 0x3c, 0x94, 0x91, 0x68, 0xb0, 0x69,
0x5a, 0x2a, 0x75, 0x0e, 0x7d, 0x19, 0x41, 0x52, 0xfa, 0xd2, 0x2a, 0x4d, 0x01, 0xb0, 0x12, 0x2a,
0xf5, 0x60, 0x83, 0x8b, 0x83, 0x1f, 0x84, 0xdc, 0x20, 0xd1, 0x90, 0x72, 0x05, 0x0d, 0xe5, 0x26,
0x1e, 0xf0, 0x6a, 0xfa, 0x80, 0x37, 0xbf, 0x4e, 0xce, 0xb8, 0x43, 0x87, 0x36, 0xcf, 0x97, 0x74,
0x69, 0x79, 0x04, 0xc5, 0x30, 0x66, 0x17, 0x8b, 0x78, 0xb4, 0x83, 0xbb, 0x91, 0x69, 0x26, 0x7b,
0x14, 0xd9, 0xcd, 0x7b, 0xa1, 0x64, 0x77, 0x68, 0x87, 0x8c, 0xb9, 0x4c, 0x56, 0x1c, 0x92, 0x2e,
0x5c, 0x3f, 0x24, 0xe7, 0xd4, 0x08, 0x0e, 0x37, 0x26, 0x8a, 0x87, 0x50, 0x14, 0x94, 0x47, 0x08,
0x8c, 0x53, 0x45, 0x64, 0x62, 0x7e, 0x05, 0xdb, 0x1c, 0x98, 0x64, 0x3b, 0x5e, 0xa3, 0x36, 0xb2,
0x77, 0x05, 0xf5, 0xc2, 0x5d, 0xc1, 0x7c, 0x9e, 0x83, 0xfb, 0x69, 0x78, 0x96, 0x79, 0x1f, 0x7a,
0x23, 0xab, 0x95, 0x7b, 0x23, 0x5a, 0xc9, 0x40, 0xb2, 0x2c, 0xc1, 0xfc, 0xa8, 0xc0, 0xee, 0x44,
0x44, 0x56, 0x44, 0x35, 0x3f, 0x29, 0xb0, 0x7d, 0x4c, 0x03, 0xec, 0x74, 0x17, 0x7a, 0x1e, 0xc6,
0x22, 0xcb, 0x5d, 0xed, 0xcd, 0xa7, 0xce, 0x86, 0xb8, 0x59, 0x87, 0x9d, 0x4c, 0x94, 0x12, 0xbf,
0xa4, 0x70, 0x2a, 0x97, 0x16, 0xce, 0xbf, 0xd8, 0x06, 0x1e, 0x59, 0x65, 0x91, 0x4a, 0x36, 0x73,
0xc6, 0xe9, 0x6d, 0xa5, 0x4e, 0x2c, 0xb9, 0xf9, 0x69, 0x6f, 0xaa, 0xb5, 0x19, 0x51, 0x6a, 0xc0,
0x0b, 0x63, 0xf3, 0x9b, 0x03, 0xab, 0xbf, 0x99, 0x76, 0x47, 0xd6, 0x5a, 0x78, 0x3b, 0x5f, 0x0b,
0x60, 0xd9, 0x3a, 0x94, 0xbf, 0xf4, 0xcd, 0x32, 0x2b, 0x76, 0x4f, 0x61, 0x6f, 0x72, 0xbe, 0x73,
0x00, 0xf8, 0xaf, 0x02, 0x2f, 0x66, 0x17, 0x5c, 0xe4, 0xf9, 0x70, 0x2d, 0xf0, 0x8d, 0xbe, 0x09,
0xf2, 0x73, 0xbc, 0x09, 0x66, 0x85, 0xf3, 0x03, 0xb8, 0x3f, 0x29, 0xfb, 0x39, 0xc0, 0x7c, 0x07,
0xca, 0x87, 0xf8, 0xcc, 0xf5, 0xe6, 0x82, 0xce, 0x7c, 0x1b, 0x2a, 0x72, 0xb6, 0x74, 0x9d, 0xaa,
0xa6, 0xca, 0xf4, 0x6a, 0x6a, 0x9e, 0x43, 0xa5, 0xee, 0x77, 0xbb, 0x2e, 0xbd, 0xe9, 0x33, 0xcc,
0xdc, 0x84, 0x6a, 0xe4, 0x49, 0x84, 0x69, 0x7e, 0x06, 0x1b, 0xc8, 0xef, 0x74, 0x4e, 0x9d, 0x66,
0xfb, 0xc6, 0xbd, 0xeb, 0xb0, 0x99, 0xf8, 0x92, 0xfe, 0x7f, 0x53, 0x60, 0xeb, 0xb8, 0xd7, 0x71,
0xa9, 0xa4, 0x64, 0x9e, 0x10, 0xa6, 0x5d, 0x2a, 0x66, 0x7e, 0xf9, 0xb0, 0x5d, 0x4f, 0xc2, 0x38,
0xe4, 0xe3, 0x46, 0xbe, 0x7e, 0x34, 0xde, 0x27, 0x9e, 0x35, 0xe1, 0x85, 0x3e, 0x32, 0xe9, 0x7b,
0x94, 0xcb, 0x54, 0x45, 0x20, 0x2d, 0x58, 0x8f, 0xf9, 0xab, 0x0a, 0x7a, 0x3a, 0x19, 0x29, 0x85,
0x37, 0x59, 0x05, 0x0e, 0x7b, 0x09, 0x4b, 0x25, 0xdc, 0x0d, 0xbb, 0x31, 0x42, 0x17, 0x6c, 0xad,
0x67, 0x4e, 0xc0, 0x24, 0x29, 0xcc, 0x8d, 0x4f, 0xa1, 0x1c, 0x69, 0x3a, 0xec, 0x1f, 0x49, 0x54,
0x99, 0xba, 0xed, 0x72, 0x33, 0x6c, 0x3b, 0xe3, 0x5d, 0x28, 0xf1, 0xea, 0x7d, 0xe9, 0xda, 0xc9,
0x11, 0x92, 0x4b, 0x1f, 0x21, 0xc6, 0x9f, 0x0a, 0xe4, 0xf9, 0xe4, 0x99, 0xef, 0x7f, 0x1f, 0x42,
0x35, 0x8e, 0xd2, 0xee, 0xb1, 0xa9, 0x52, 0x34, 0x0f, 0xa6, 0x40, 0x92, 0x86, 0x00, 0x95, 0xdb,
0x69, 0x40, 0xea, 0x00, 0xe2, 0xbf, 0xe2, 0x7c, 0x29, 0x41, 0xf1, 0xcb, 0x53, 0x96, 0x8a, 0xd3,
0x45, 0x25, 0x12, 0x67, 0xae, 0x43, 0x9e, 0xb8, 0x5f, 0x8a, 0x9b, 0x99, 0x8a, 0xf8, 0xb7, 0xf9,
0x18, 0x76, 0xde, 0xc7, 0xf4, 0x38, 0x18, 0x44, 0x25, 0x3a, 0x52, 0xe6, 0x14, 0x98, 0x4c, 0x04,
0x77, 0xb2, 0x93, 0xa4, 0x02, 0xde, 0x62, 0xe2, 0x0a, 0x06, 0xf6, 0xc8, 0x4c, 0xed, 0x60, 0x27,
0xa1, 0x27, 0x3d, 0x49, 0x23, 0x49, 0xe3, 0xd0, 0x80, 0x5a, 0xd3, 0xef, 0x5a, 0x43, 0xbf, 0x4f,
0xfb, 0xa7, 0xd8, 0x1a, 0xb8, 0x94, 0x6d, 0x26, 0xf1, 0x33, 0xc2, 0x69, 0x81, 0xff, 0x79, 0xfc,
0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc3, 0xa6, 0x7a, 0xd8, 0x8f, 0x18, 0x00, 0x00,
// 1316 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xd4, 0x59, 0x4f, 0x6f, 0xe3, 0x44,
0x14, 0x97, 0xe3, 0x34, 0x69, 0x9e, 0x93, 0xb4, 0xeb, 0x6d, 0x77, 0x43, 0x58, 0xb6, 0xc5, 0x02,
0x6d, 0x81, 0x95, 0xa5, 0xcd, 0xf2, 0x4f, 0x08, 0x09, 0x68, 0xa8, 0x50, 0xb4, 0xb0, 0x2a, 0xd3,
0x0a, 0x71, 0x00, 0x59, 0x6e, 0x32, 0x6a, 0x4d, 0x13, 0x3b, 0x78, 0xc6, 0x81, 0x72, 0xe0, 0x86,
0xc4, 0x6d, 0x0f, 0x08, 0x09, 0x21, 0x2e, 0x7c, 0x04, 0xbe, 0x01, 0x9c, 0x38, 0x72, 0xe0, 0xc0,
0x8d, 0x8f, 0x00, 0x5f, 0x80, 0x03, 0xe3, 0x99, 0xf1, 0x9f, 0xb8, 0x49, 0x9a, 0x26, 0x6d, 0x95,
0x9e, 0xea, 0x99, 0xf7, 0x66, 0xde, 0x7b, 0xbf, 0xdf, 0x9b, 0x37, 0xf3, 0x1a, 0x28, 0x0f, 0xe8,
0xa1, 0x4d, 0xb1, 0xd9, 0xf7, 0x3d, 0xea, 0xe9, 0x05, 0x31, 0xaa, 0x6b, 0x9f, 0x07, 0xd8, 0x3f,
0x11, 0x93, 0xf5, 0x2a, 0xf5, 0xfa, 0x5e, 0xc7, 0xa6, 0xb6, 0x1c, 0x6b, 0x03, 0xea, 0xf7, 0xdb,
0x62, 0x60, 0xfc, 0xa9, 0x40, 0x71, 0x0f, 0x13, 0xe2, 0x78, 0xae, 0xfe, 0x3c, 0x54, 0x1d, 0xd7,
0xa2, 0xbe, 0xed, 0x12, 0xbb, 0x4d, 0xd9, 0x4c, 0x4d, 0xd9, 0x54, 0xb6, 0x96, 0x51, 0xc5, 0x71,
0xf7, 0x93, 0x49, 0xbd, 0x09, 0x55, 0x72, 0x64, 0xfb, 0x1d, 0x8b, 0x88, 0x75, 0xa4, 0x96, 0xdb,
0x54, 0xb7, 0xb4, 0xc6, 0x1d, 0x53, 0xfa, 0x22, 0xf7, 0x33, 0xf7, 0x42, 0x2d, 0x39, 0x40, 0x15,
0x92, 0x1a, 0x91, 0xfa, 0x27, 0x50, 0x4e, 0x8b, 0x99, 0xed, 0x02, 0xb5, 0xfd, 0x43, 0x4c, 0xb9,
0x4d, 0xad, 0x51, 0x31, 0x45, 0x08, 0xfb, 0x7c, 0x12, 0x49, 0x61, 0xe8, 0x62, 0xca, 0x3f, 0xcb,
0xe9, 0x30, 0xdb, 0xca, 0x96, 0x8a, 0x2a, 0xa9, 0xd9, 0x56, 0xc7, 0xf8, 0x2e, 0x07, 0xd5, 0x9d,
0x2f, 0x71, 0x3b, 0xa0, 0x18, 0x61, 0xb6, 0x11, 0xa1, 0xfa, 0x7d, 0x28, 0xb5, 0xed, 0x6e, 0x17,
0xfb, 0xe1, 0x22, 0x61, 0x63, 0xc5, 0x14, 0x48, 0x34, 0xf9, 0x7c, 0xeb, 0x5d, 0xb4, 0x2c, 0x34,
0x5a, 0x1d, 0xfd, 0x05, 0x28, 0xca, 0xe8, 0xb8, 0x01, 0xa1, 0x9b, 0x0e, 0x0e, 0x45, 0x72, 0xfd,
0x1e, 0x2c, 0x71, 0x57, 0x6b, 0x2a, 0x57, 0xbc, 0x21, 0x1d, 0xdf, 0xf6, 0x02, 0xb7, 0xf3, 0x61,
0xf8, 0x89, 0x84, 0x5c, 0x7f, 0x05, 0x34, 0x6a, 0x1f, 0x74, 0x31, 0xb5, 0xe8, 0x49, 0x1f, 0xd7,
0xf2, 0x4c, 0xbd, 0xda, 0x58, 0x33, 0x63, 0x76, 0xf6, 0xb9, 0x70, 0x9f, 0xc9, 0x10, 0xd0, 0xf8,
0x9b, 0x39, 0xae, 0xbb, 0x1e, 0xb5, 0x32, 0xcc, 0x2c, 0x71, 0x66, 0x56, 0x99, 0xa4, 0x35, 0x44,
0x4e, 0x1d, 0x96, 0x8f, 0xf1, 0x09, 0xe9, 0xdb, 0x6d, 0x5c, 0x2b, 0x30, 0x9d, 0x12, 0x8a, 0xc7,
0xc6, 0x13, 0x05, 0x56, 0x62, 0x54, 0x48, 0x9f, 0xd1, 0x80, 0x19, 0xa0, 0x4b, 0xd8, 0xf7, 0x3d,
0x3f, 0x03, 0x09, 0xda, 0x6d, 0xee, 0x84, 0xd3, 0x48, 0x48, 0xcf, 0x83, 0xc7, 0x8b, 0x50, 0xf0,
0x31, 0x09, 0xba, 0x54, 0x02, 0xa2, 0x4b, 0x40, 0x04, 0x16, 0x5c, 0x82, 0xa4, 0x86, 0xf1, 0x4b,
0x0e, 0xd6, 0xa4, 0x47, 0x3c, 0x1b, 0xc8, 0xe2, 0xb0, 0x95, 0x06, 0x32, 0x3f, 0x0c, 0xa4, 0x7e,
0x0b, 0x0a, 0x3c, 0x9b, 0x09, 0xa3, 0x41, 0x65, 0x12, 0x39, 0xca, 0x32, 0x5c, 0x98, 0x8b, 0xe1,
0xe2, 0x68, 0x86, 0x8d, 0xef, 0x15, 0x58, 0xcf, 0x60, 0xb6, 0x10, 0x5c, 0xfe, 0x96, 0x83, 0xa7,
0xa4, 0x5f, 0x8f, 0x24, 0x50, 0xad, 0xeb, 0x42, 0xe8, 0xb3, 0x50, 0x8e, 0xbe, 0x99, 0x7f, 0x82,
0xd6, 0x32, 0xd2, 0x8e, 0x93, 0x38, 0xae, 0x86, 0xdb, 0x1f, 0x15, 0xa8, 0x8f, 0xc2, 0x70, 0x21,
0x08, 0xfe, 0x23, 0x07, 0xb7, 0x13, 0xe7, 0x90, 0xed, 0x1e, 0xe2, 0x6b, 0x42, 0xef, 0x03, 0x00,
0xf6, 0x6d, 0xf9, 0xdc, 0x65, 0x4e, 0x6e, 0x18, 0x69, 0x4c, 0x5d, 0x14, 0x0d, 0x2a, 0x1d, 0x47,
0x71, 0x5d, 0x0d, 0xdd, 0x3f, 0x28, 0x50, 0x3b, 0x8d, 0xe8, 0x42, 0x90, 0xfd, 0x6d, 0x3e, 0x26,
0x7b, 0xc7, 0xa5, 0x0e, 0x3d, 0xb9, 0x36, 0x67, 0x99, 0x51, 0x80, 0xb9, 0xc7, 0x56, 0xdb, 0xeb,
0x06, 0x3d, 0xd7, 0x72, 0xed, 0x1e, 0xe6, 0xf7, 0x65, 0x09, 0xad, 0x0a, 0x49, 0x93, 0x0b, 0x1e,
0xb3, 0x79, 0xfd, 0x63, 0xb8, 0x29, 0xb5, 0x87, 0x0a, 0x40, 0x81, 0xe7, 0xc8, 0x56, 0xe4, 0xe9,
0x18, 0x24, 0xcc, 0x68, 0x02, 0xdd, 0x10, 0x9b, 0x3c, 0x1a, 0x5f, 0x30, 0x8a, 0x73, 0x65, 0xd0,
0xf2, 0xe8, 0x0c, 0xaa, 0x1f, 0xc0, 0x72, 0xe4, 0x83, 0xbe, 0x01, 0x79, 0x6e, 0x49, 0xe1, 0x96,
0xb4, 0xe8, 0x01, 0x15, 0x1a, 0xe0, 0x02, 0x7d, 0x0d, 0x96, 0x06, 0x76, 0x37, 0xc0, 0x9c, 0x87,
0x32, 0x12, 0x03, 0xb6, 0x4c, 0x4b, 0x85, 0xce, 0xa1, 0x2f, 0x23, 0x48, 0x4a, 0x5f, 0x3a, 0x4b,
0x53, 0x00, 0x2c, 0x44, 0x96, 0xba, 0xb0, 0xc2, 0x93, 0x83, 0x5f, 0x84, 0x5c, 0x21, 0xc9, 0x21,
0xe5, 0x1c, 0x39, 0x94, 0x1b, 0x7b, 0xc1, 0xab, 0xe9, 0x0b, 0xde, 0xf8, 0x26, 0xb9, 0xe3, 0xb6,
0x6d, 0xda, 0x3e, 0xba, 0xa2, 0x47, 0xcb, 0x03, 0x28, 0x86, 0x3e, 0x3b, 0x58, 0xf8, 0xa3, 0x35,
0x6e, 0x47, 0xaa, 0x99, 0xe8, 0x51, 0xa4, 0x37, 0xeb, 0x63, 0x93, 0xbd, 0xaf, 0x6d, 0x32, 0xe2,
0xa1, 0x59, 0xb1, 0x49, 0xba, 0x70, 0xfd, 0x94, 0xdc, 0x53, 0x43, 0x38, 0x5c, 0x5a, 0x52, 0xdc,
0x87, 0xa2, 0xa0, 0x3c, 0x42, 0x60, 0x54, 0x56, 0x44, 0x2a, 0xc6, 0xd7, 0xb0, 0xc6, 0x81, 0x49,
0x8e, 0xe3, 0x05, 0xe6, 0x46, 0xf6, 0xad, 0xa0, 0x9e, 0x7a, 0x2b, 0x18, 0x4f, 0x72, 0x70, 0x37,
0x0d, 0xcf, 0x55, 0xbe, 0x87, 0x5e, 0xcd, 0xe6, 0xca, 0x9d, 0xa1, 0x5c, 0xc9, 0x40, 0x72, 0x55,
0x09, 0xf3, 0xb3, 0x02, 0x1b, 0x63, 0x11, 0x59, 0x90, 0xac, 0xf9, 0x55, 0x81, 0xb5, 0x3d, 0xea,
0x63, 0xbb, 0x37, 0x57, 0xeb, 0x18, 0x27, 0x59, 0xee, 0x7c, 0xfd, 0xa0, 0x3a, 0x25, 0xe2, 0x13,
0xee, 0x3e, 0xa3, 0x09, 0xeb, 0x99, 0x08, 0x24, 0xb6, 0x49, 0x51, 0x55, 0xce, 0x2c, 0xaa, 0x7f,
0xb3, 0xc3, 0x3d, 0xb4, 0xcb, 0x3c, 0x55, 0x6e, 0x6a, 0x34, 0xd2, 0x61, 0xa9, 0x63, 0xcb, 0x71,
0x7e, 0x52, 0xbf, 0xb5, 0x34, 0x1d, 0x82, 0x46, 0x0b, 0x9e, 0x1e, 0x19, 0xdf, 0x0c, 0x58, 0xfd,
0xc3, 0xf2, 0x7a, 0x68, 0xaf, 0xb9, 0x8f, 0xfa, 0x85, 0x00, 0x96, 0xad, 0x51, 0xf9, 0x33, 0xfb,
0x99, 0x69, 0xb1, 0x7b, 0x0c, 0x9b, 0xe3, 0xe3, 0x9d, 0x01, 0xc0, 0xff, 0x14, 0x78, 0x26, 0xbb,
0xe1, 0x3c, 0xad, 0xc5, 0x85, 0xc0, 0x37, 0xdc, 0x2f, 0xe4, 0x67, 0xe8, 0x17, 0xa6, 0x85, 0xf3,
0x7d, 0xb8, 0x3b, 0x2e, 0xfa, 0x19, 0xc0, 0x7c, 0x13, 0xca, 0xdb, 0xf8, 0xd0, 0x71, 0x67, 0x82,
0xce, 0x78, 0x03, 0x2a, 0x72, 0xb5, 0x34, 0x9d, 0xaa, 0xb4, 0xca, 0xe4, 0x4a, 0x6b, 0x1c, 0x41,
0xa5, 0xe9, 0xf5, 0x7a, 0x0e, 0xbd, 0xec, 0xfb, 0xcd, 0x58, 0x85, 0x6a, 0x64, 0x49, 0xb8, 0x69,
0x7c, 0x06, 0x2b, 0xc8, 0xeb, 0x76, 0x0f, 0xec, 0xf6, 0xf1, 0xa5, 0x5b, 0xd7, 0x61, 0x35, 0xb1,
0x25, 0xed, 0xff, 0x9b, 0x83, 0x1b, 0x7b, 0xfd, 0xae, 0x43, 0x25, 0x25, 0xb3, 0xb8, 0x30, 0xe9,
0xc1, 0x31, 0x75, 0x57, 0xc4, 0x4e, 0x3d, 0x09, 0xfd, 0x90, 0x8d, 0x8f, 0x2c, 0x96, 0x1a, 0x9f,
0x13, 0x2d, 0x4f, 0xf8, 0xd8, 0x8f, 0x54, 0x02, 0x97, 0xf2, 0x34, 0x55, 0x11, 0x48, 0x0d, 0x36,
0xa3, 0xbf, 0x0c, 0xb7, 0xdd, 0xa0, 0x67, 0xf9, 0xde, 0x17, 0xc4, 0xea, 0x33, 0xe7, 0xf9, 0xce,
0x56, 0xdf, 0xf6, 0x29, 0xef, 0x81, 0x55, 0x74, 0x93, 0x89, 0x11, 0x93, 0xee, 0x62, 0x9f, 0x1b,
0xdf, 0x65, 0x22, 0xfd, 0x6d, 0x28, 0xd9, 0xdd, 0x43, 0xcf, 0x77, 0xe8, 0x51, 0x4f, 0x76, 0x3a,
0x86, 0x74, 0xf3, 0x14, 0x32, 0xe6, 0x3b, 0x91, 0x26, 0x4a, 0x16, 0xe9, 0x2f, 0x81, 0x1e, 0x10,
0x6c, 0x09, 0xe7, 0x84, 0xd1, 0x41, 0x43, 0xb6, 0x3d, 0x2b, 0x4c, 0x92, 0x6c, 0xf3, 0x51, 0xc3,
0xf8, 0x5d, 0x05, 0x3d, 0xbd, 0xaf, 0xcc, 0xd7, 0xd7, 0xd8, 0x35, 0x11, 0xce, 0x12, 0x86, 0x77,
0x78, 0x64, 0x37, 0x62, 0x1a, 0x4f, 0xe9, 0x9a, 0xa1, 0xdb, 0x48, 0xaa, 0xd7, 0x3f, 0x85, 0x72,
0x74, 0xf0, 0x78, 0x38, 0x69, 0x36, 0x94, 0x89, 0xb5, 0x21, 0x37, 0x45, 0x6d, 0xa8, 0xbf, 0x05,
0x25, 0x7e, 0xc5, 0x9c, 0xb9, 0x77, 0x72, 0xcf, 0xe5, 0xd2, 0xf7, 0x5c, 0xfd, 0x2f, 0x05, 0xf2,
0x7c, 0xf1, 0xd4, 0x0f, 0xd8, 0x0f, 0xa0, 0x1a, 0x7b, 0x29, 0xd8, 0x13, 0x99, 0x7d, 0x6f, 0x02,
0x24, 0x69, 0x08, 0x50, 0xf9, 0x38, 0x0d, 0x48, 0x13, 0x40, 0xfc, 0xcb, 0x9f, 0x6f, 0x25, 0xf2,
0xf0, 0xb9, 0x09, 0x5b, 0xc5, 0xe1, 0xa2, 0x12, 0x89, 0x23, 0xd7, 0x21, 0x4f, 0x9c, 0xaf, 0xc4,
0xa3, 0x45, 0x45, 0xfc, 0xdb, 0x78, 0x08, 0xeb, 0xef, 0x61, 0xba, 0xe7, 0x0f, 0xa2, 0x7b, 0x24,
0x3a, 0x3e, 0x13, 0x60, 0x32, 0x10, 0xdc, 0xca, 0x2e, 0x92, 0x19, 0xf0, 0x3a, 0x3b, 0x01, 0xfe,
0xc0, 0x1a, 0x5a, 0xa9, 0x35, 0xd6, 0x13, 0x7a, 0xd2, 0x8b, 0x34, 0x92, 0x0c, 0xb6, 0xeb, 0x50,
0x6b, 0x7b, 0x3d, 0xf3, 0xc4, 0x0b, 0x68, 0x70, 0x80, 0xcd, 0x81, 0x43, 0xd9, 0x89, 0x17, 0xbf,
0x91, 0x1c, 0x14, 0xf8, 0x9f, 0x87, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x12, 0x77, 0x8b, 0xc2,
0x6c, 0x19, 0x00, 0x00,
}

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

@ -202,6 +202,17 @@ func (ftc *fakeTabletConn) SplitQuery(ctx context.Context, query querytypes.Boun
return nil, fmt.Errorf("not implemented in this test")
}
// SplitQuery is part of the TabletConn interface
func (ftc *fakeTabletConn) SplitQueryV2(
ctx context.Context,
query querytypes.BoundQuery,
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]querytypes.QuerySplit, error) {
return nil, fmt.Errorf("not implemented in this test")
}
type streamHealthReader struct {
c <-chan *querypb.StreamHealthResponse
err *error

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

@ -152,11 +152,24 @@ func (q *query) SplitQuery(ctx context.Context, request *querypb.SplitQueryReque
request.EffectiveCallerId,
request.ImmediateCallerId,
)
bq, err := querytypes.Proto3ToBoundQuery(request.Query)
if err != nil {
return nil, tabletserver.ToGRPCError(err)
}
splits, err := q.server.SplitQuery(ctx, request.Target, bq.Sql, bq.BindVariables, request.SplitColumn, request.SplitCount, request.SessionId)
splits := []querytypes.QuerySplit{}
splits, err = queryservice.CallCorrectSplitQuery(
q.server,
request.UseSplitQueryV2,
ctx,
request.Target,
bq.Sql,
bq.BindVariables,
request.SplitColumn,
request.SplitCount,
request.NumRowsPerQueryPart,
request.Algorithm,
request.SessionId)
if err != nil {
return nil, tabletserver.ToGRPCError(err)
}

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

@ -251,6 +251,8 @@ func (conn *gRPCQueryClient) Rollback(ctx context.Context, transactionID int64)
}
// SplitQuery is the stub for TabletServer.SplitQuery RPC
// TODO(erez): Remove this method and rename SplitQueryV2 to SplitQuery once
// the migration to SplitQuery V2 is done.
func (conn *gRPCQueryClient) SplitQuery(ctx context.Context, query querytypes.BoundQuery, splitColumn string, splitCount int64) (queries []querytypes.QuerySplit, err error) {
conn.mu.RLock()
defer conn.mu.RUnlock()
@ -264,13 +266,59 @@ func (conn *gRPCQueryClient) SplitQuery(ctx context.Context, query querytypes.Bo
return nil, tabletconn.TabletErrorFromGRPC(err)
}
req := &querypb.SplitQueryRequest{
Target: conn.target,
EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx),
ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx),
Query: q,
SplitColumn: splitColumn,
SplitCount: splitCount,
SessionId: conn.sessionID,
Target: conn.target,
EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx),
ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx),
Query: q,
SplitColumn: []string{splitColumn},
SplitCount: splitCount,
NumRowsPerQueryPart: 0,
Algorithm: querypb.SplitQueryRequest_EQUAL_SPLITS,
UseSplitQueryV2: false,
SessionId: conn.sessionID,
}
sqr, err := conn.c.SplitQuery(ctx, req)
if err != nil {
return nil, tabletconn.TabletErrorFromGRPC(err)
}
split, err := querytypes.Proto3ToQuerySplits(sqr.Queries)
if err != nil {
return nil, tabletconn.TabletErrorFromGRPC(err)
}
return split, nil
}
// SplitQueryV2 is the stub for TabletServer.SplitQuery RPC
func (conn *gRPCQueryClient) SplitQueryV2(
ctx context.Context,
query querytypes.BoundQuery,
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) (queries []querytypes.QuerySplit, err error) {
conn.mu.RLock()
defer conn.mu.RUnlock()
if conn.cc == nil {
err = tabletconn.ConnClosed
return
}
q, err := querytypes.BoundQueryToProto3(query.Sql, query.BindVariables)
if err != nil {
return nil, tabletconn.TabletErrorFromGRPC(err)
}
req := &querypb.SplitQueryRequest{
Target: conn.target,
EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx),
ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx),
Query: q,
SplitColumn: splitColumns,
SplitCount: splitCount,
NumRowsPerQueryPart: numRowsPerQueryPart,
Algorithm: algorithm,
UseSplitQueryV2: true,
SessionId: conn.sessionID,
}
sqr, err := conn.c.SplitQuery(ctx, req)
if err != nil {

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

@ -288,7 +288,7 @@ func (qre *QueryExecutor) checkPermissions() error {
if qre.qe.strictTableAcl {
errStr := fmt.Sprintf("table acl error: %q cannot run %v on table %q", callerID.Username, qre.plan.PlanID, qre.plan.TableName)
qre.qe.tableaclDenied.Add(tableACLStatsKey, 1)
qre.qe.accessCheckerLogger.Errorf("%s", errStr)
qre.qe.accessCheckerLogger.Infof("%s", errStr)
return NewTabletError(ErrFail, vtrpcpb.ErrorCode_PERMISSION_DENIED, "%s", errStr)
}
return nil

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

@ -41,8 +41,24 @@ type QueryService interface {
ExecuteBatch(ctx context.Context, target *querypb.Target, queries []querytypes.BoundQuery, sessionID int64, asTransaction bool, transactionID int64) ([]sqltypes.Result, error)
// SplitQuery is a map reduce helper function
// TODO(erez): Remove this and rename the following func to SplitQuery
// once we migrate to SplitQuery V2.
SplitQuery(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]interface{}, splitColumn string, splitCount int64, sessionID int64) ([]querytypes.QuerySplit, error)
// SplitQueryV2 is a MapReduce helper function.
// This is version of SplitQuery supports multiple algorithms and multiple split columns.
// See the documentation of SplitQueryRequest in 'proto/vtgate.proto' for more information.
SplitQueryV2(
ctx context.Context,
target *querypb.Target,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
sessionID int64) ([]querytypes.QuerySplit, error)
// StreamHealthRegister registers a listener for StreamHealth
StreamHealthRegister(chan<- *querypb.StreamHealthResponse) (int, error)
@ -96,10 +112,25 @@ func (e *ErrorQueryService) ExecuteBatch(ctx context.Context, target *querypb.Ta
}
// SplitQuery is part of QueryService interface
// TODO(erez): Remove once the migration to SplitQuery V2 is done.
func (e *ErrorQueryService) SplitQuery(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]interface{}, splitColumn string, splitCount int64, sessionID int64) ([]querytypes.QuerySplit, error) {
return nil, fmt.Errorf("ErrorQueryService does not implement any method")
}
// SplitQuery is part of QueryService interface
func (e *ErrorQueryService) SplitQueryV2(
ctx context.Context,
target *querypb.Target,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
sessionID int64) ([]querytypes.QuerySplit, error) {
return nil, fmt.Errorf("ErrorQueryService does not implement any method")
}
// StreamHealthRegister is part of QueryService interface
func (e *ErrorQueryService) StreamHealthRegister(chan<- *querypb.StreamHealthResponse) (int, error) {
return 0, fmt.Errorf("ErrorQueryService does not implement any method")
@ -116,3 +147,59 @@ func (e *ErrorQueryService) HandlePanic(*error) {
// make sure ErrorQueryService implements QueryService
var _ QueryService = &ErrorQueryService{}
// CallCorrectSplitQuery calls the correct SplitQuery.
// This trivial logic is encapsulated in a function here so it can be easily tested.
// TODO(erez): Remove once the migration to SplitQueryV2 is done.
func CallCorrectSplitQuery(
queryService QueryService,
useSplitQueryV2 bool,
ctx context.Context,
target *querypb.Target,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
sessionID int64) ([]querytypes.QuerySplit, error) {
if useSplitQueryV2 {
return queryService.SplitQueryV2(
ctx,
target,
sql,
bindVariables,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm,
sessionID)
}
return queryService.SplitQuery(
ctx,
target,
sql,
bindVariables,
splitColumnsToSplitColumn(splitColumns),
splitCount,
sessionID)
}
// SplitColumnsToSplitColumn returns the first SplitColumn in the given slice or an empty
// string if the slice is empty.
//
// This method is used to get the traditional behavior when accessing the SplitColumn field in an
// older SplitQuery-V1 querypb.SplitQueryRequest represented in the newer SplitQuery-V2
// querypb.SplitQueryRequest message. In the new V2 message the SplitColumn field has been converted
// into a repeated string field.
// TODO(erez): Remove this function when migration to SplitQueryV2 is done.
func splitColumnsToSplitColumn(splitColumns []string) string {
if len(splitColumns) == 0 {
return ""
}
return splitColumns[0]
}
// Command to generate a mock for this interface with mockgen.
//go:generate mockgen -source $GOFILE -destination queryservice_testing/mock_queryservice.go -package queryservice_testing

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

@ -0,0 +1,104 @@
package queryservice
import (
"testing"
"github.com/golang/mock/gomock"
"golang.org/x/net/context"
querypb "github.com/youtube/vitess/go/vt/proto/query"
"github.com/youtube/vitess/go/vt/tabletserver/queryservice/queryservice_testing"
)
var (
target querypb.Target
sql = "It's an SQL statement!"
bindVariables = map[string]interface{}{}
splitCount int64 = 123
numRowsPerQueryPart int64 = 456
sessionID int64 = 789
algorithm = querypb.SplitQueryRequest_EQUAL_SPLITS
)
func TestCallCorrectSplitQueryCallV1NoSplitColumn(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockQueryService := queryservice_testing.NewMockQueryService(mockCtrl)
mockQueryService.EXPECT().SplitQuery(
context.Background(),
&target,
sql,
bindVariables,
"",
splitCount,
sessionID)
CallCorrectSplitQuery(
mockQueryService,
false, /* useSplitQueryV2 */
context.Background(),
&target,
sql,
bindVariables,
[]string{}, /* SplitColumns */
splitCount,
numRowsPerQueryPart,
algorithm,
sessionID)
}
func TestCallCorrectSplitQueryCallV1WithSplitColumn(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockQueryService := queryservice_testing.NewMockQueryService(mockCtrl)
mockQueryService.EXPECT().SplitQuery(
context.Background(),
&target,
sql,
bindVariables,
"First Split Column",
splitCount,
sessionID)
CallCorrectSplitQuery(
mockQueryService,
false, /* useSplitQueryV2 */
context.Background(),
&target,
sql,
bindVariables,
[]string{"First Split Column"}, /* SplitColumns */
splitCount,
numRowsPerQueryPart,
algorithm,
sessionID)
}
func TestCallCorrectSplitQueryCallV2(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockQueryService := queryservice_testing.NewMockQueryService(mockCtrl)
splitColumns := []string{"col1", "col2"}
mockQueryService.EXPECT().SplitQueryV2(
context.Background(),
&target,
sql,
bindVariables,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm,
sessionID)
CallCorrectSplitQuery(
mockQueryService,
true, /* useSplitQueryV2 */
context.Background(),
&target,
sql,
bindVariables,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm,
sessionID)
}

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

@ -0,0 +1,158 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: queryservice.go
package queryservice_testing
import (
gomock "github.com/golang/mock/gomock"
sqltypes "github.com/youtube/vitess/go/sqltypes"
query "github.com/youtube/vitess/go/vt/proto/query"
querytypes "github.com/youtube/vitess/go/vt/tabletserver/querytypes"
context "golang.org/x/net/context"
)
// Mock of QueryService interface
type MockQueryService struct {
ctrl *gomock.Controller
recorder *_MockQueryServiceRecorder
}
// Recorder for MockQueryService (not exported)
type _MockQueryServiceRecorder struct {
mock *MockQueryService
}
func NewMockQueryService(ctrl *gomock.Controller) *MockQueryService {
mock := &MockQueryService{ctrl: ctrl}
mock.recorder = &_MockQueryServiceRecorder{mock}
return mock
}
func (_m *MockQueryService) EXPECT() *_MockQueryServiceRecorder {
return _m.recorder
}
func (_m *MockQueryService) GetSessionId(keyspace string, shard string) (int64, error) {
ret := _m.ctrl.Call(_m, "GetSessionId", keyspace, shard)
ret0, _ := ret[0].(int64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockQueryServiceRecorder) GetSessionId(arg0, arg1 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "GetSessionId", arg0, arg1)
}
func (_m *MockQueryService) Begin(ctx context.Context, target *query.Target, sessionID int64) (int64, error) {
ret := _m.ctrl.Call(_m, "Begin", ctx, target, sessionID)
ret0, _ := ret[0].(int64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockQueryServiceRecorder) Begin(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Begin", arg0, arg1, arg2)
}
func (_m *MockQueryService) Commit(ctx context.Context, target *query.Target, sessionID int64, transactionID int64) error {
ret := _m.ctrl.Call(_m, "Commit", ctx, target, sessionID, transactionID)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockQueryServiceRecorder) Commit(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Commit", arg0, arg1, arg2, arg3)
}
func (_m *MockQueryService) Rollback(ctx context.Context, target *query.Target, sessionID int64, transactionID int64) error {
ret := _m.ctrl.Call(_m, "Rollback", ctx, target, sessionID, transactionID)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockQueryServiceRecorder) Rollback(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Rollback", arg0, arg1, arg2, arg3)
}
func (_m *MockQueryService) Execute(ctx context.Context, target *query.Target, sql string, bindVariables map[string]interface{}, sessionID int64, transactionID int64) (*sqltypes.Result, error) {
ret := _m.ctrl.Call(_m, "Execute", ctx, target, sql, bindVariables, sessionID, transactionID)
ret0, _ := ret[0].(*sqltypes.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockQueryServiceRecorder) Execute(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Execute", arg0, arg1, arg2, arg3, arg4, arg5)
}
func (_m *MockQueryService) StreamExecute(ctx context.Context, target *query.Target, sql string, bindVariables map[string]interface{}, sessionID int64, sendReply func(*sqltypes.Result) error) error {
ret := _m.ctrl.Call(_m, "StreamExecute", ctx, target, sql, bindVariables, sessionID, sendReply)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockQueryServiceRecorder) StreamExecute(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "StreamExecute", arg0, arg1, arg2, arg3, arg4, arg5)
}
func (_m *MockQueryService) ExecuteBatch(ctx context.Context, target *query.Target, queries []querytypes.BoundQuery, sessionID int64, asTransaction bool, transactionID int64) ([]sqltypes.Result, error) {
ret := _m.ctrl.Call(_m, "ExecuteBatch", ctx, target, queries, sessionID, asTransaction, transactionID)
ret0, _ := ret[0].([]sqltypes.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockQueryServiceRecorder) ExecuteBatch(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "ExecuteBatch", arg0, arg1, arg2, arg3, arg4, arg5)
}
func (_m *MockQueryService) SplitQuery(ctx context.Context, target *query.Target, sql string, bindVariables map[string]interface{}, splitColumn string, splitCount int64, sessionID int64) ([]querytypes.QuerySplit, error) {
ret := _m.ctrl.Call(_m, "SplitQuery", ctx, target, sql, bindVariables, splitColumn, splitCount, sessionID)
ret0, _ := ret[0].([]querytypes.QuerySplit)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockQueryServiceRecorder) SplitQuery(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "SplitQuery", arg0, arg1, arg2, arg3, arg4, arg5, arg6)
}
func (_m *MockQueryService) SplitQueryV2(ctx context.Context, target *query.Target, sql string, bindVariables map[string]interface{}, splitColumns []string, splitCount int64, numRowsPerQueryPart int64, algorithm query.SplitQueryRequest_Algorithm, sessionID int64) ([]querytypes.QuerySplit, error) {
ret := _m.ctrl.Call(_m, "SplitQueryV2", ctx, target, sql, bindVariables, splitColumns, splitCount, numRowsPerQueryPart, algorithm, sessionID)
ret0, _ := ret[0].([]querytypes.QuerySplit)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockQueryServiceRecorder) SplitQueryV2(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "SplitQueryV2", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
}
func (_m *MockQueryService) StreamHealthRegister(_param0 chan<- *query.StreamHealthResponse) (int, error) {
ret := _m.ctrl.Call(_m, "StreamHealthRegister", _param0)
ret0, _ := ret[0].(int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockQueryServiceRecorder) StreamHealthRegister(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "StreamHealthRegister", arg0)
}
func (_m *MockQueryService) StreamHealthUnregister(_param0 int) error {
ret := _m.ctrl.Call(_m, "StreamHealthUnregister", _param0)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockQueryServiceRecorder) StreamHealthUnregister(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "StreamHealthUnregister", arg0)
}
func (_m *MockQueryService) HandlePanic(_param0 *error) {
_m.ctrl.Call(_m, "HandlePanic", _param0)
}
func (_mr *_MockQueryServiceRecorder) HandlePanic(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "HandlePanic", arg0)
}

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

@ -4,7 +4,6 @@ import (
"fmt"
"github.com/youtube/vitess/go/vt/schema"
"github.com/youtube/vitess/go/vt/tabletserver/querytypes"
)
func Example() {
@ -45,9 +44,8 @@ func Example() {
splitter := NewSplitter(splitParams, algorithm)
// 4. Call splitter.Split() to Split the query.
// The result is a slice of querytypes.QuerySplit objects.
var queryParts []querytypes.QuerySplit
queryParts, err = splitter.Split()
// The result is a slice of querytypes.QuerySplit objects (and an error object).
queryParts, err := splitter.Split()
if err != nil {
panic(fmt.Sprintf("splitter.Split() failed with: %v", err))
}

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

@ -116,6 +116,10 @@ func NewSplitParamsGivenSplitCount(
return result, nil
}
func (splitParams *SplitParams) GetSplitTableName() string {
return splitParams.splitTableSchema.Name
}
// newSplitParams validates and initializes all the fields except splitCount and
// numRowsPerQueryPart. It contains the common code for the constructors above.
func newSplitParams(sql string, bindVariables map[string]interface{}, splitColumns []string,

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

@ -116,6 +116,17 @@ type TabletConn interface {
// appending primary key range clauses to the original query
SplitQuery(ctx context.Context, query querytypes.BoundQuery, splitColumn string, splitCount int64) ([]querytypes.QuerySplit, error)
// SplitQuery splits a query into equally sized smaller queries by
// appending primary key range clauses to the original query
// TODO(erez): Remove SplitQuery and rename this to SplitQueryV2 once migration is done.
SplitQueryV2(
ctx context.Context,
query querytypes.BoundQuery,
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) (queries []querytypes.QuerySplit, err error)
// StreamHealth starts a streaming RPC for VTTablet health status updates.
StreamHealth(ctx context.Context) (StreamHealthReader, error)
}

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

@ -637,6 +637,52 @@ func (f *FakeQueryService) SplitQuery(ctx context.Context, target *querypb.Targe
return splitQueryQuerySplitList, nil
}
// SplitQueryV2 is part of the queryservice.QueryService interface
// TODO(erez): Rename to SplitQuery after migration to SplitQuery V2 is done.
func (f *FakeQueryService) SplitQueryV2(
ctx context.Context,
target *querypb.Target,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
sessionID int64) ([]querytypes.QuerySplit, error) {
if f.hasError {
return nil, testTabletError
}
if f.panics {
panic(fmt.Errorf("test-triggered panic"))
}
f.checkSessionTargetCallerID(ctx, "SplitQuery", target, sessionID)
if !reflect.DeepEqual(querytypes.BoundQuery{
Sql: sql,
BindVariables: bindVariables,
}, splitQueryV2BoundQuery) {
f.t.Errorf("invalid SplitQuery.SplitQueryRequest.Query: got %v expected %v",
querytypes.QueryAsString(sql, bindVariables), splitQueryBoundQuery)
}
if !reflect.DeepEqual(splitColumns, splitQueryV2SplitColumns) {
f.t.Errorf("invalid SplitQuery.SplitColumn: got %v expected %v",
splitColumns, splitQueryV2SplitColumns)
}
if !reflect.DeepEqual(splitCount, splitQueryV2SplitCount) {
f.t.Errorf("invalid SplitQuery.SplitCount: got %v expected %v",
splitCount, splitQueryV2SplitCount)
}
if !reflect.DeepEqual(numRowsPerQueryPart, splitQueryV2NumRowsPerQueryPart) {
f.t.Errorf("invalid SplitQuery.numRowsPerQueryPart: got %v expected %v",
numRowsPerQueryPart, splitQueryV2NumRowsPerQueryPart)
}
if algorithm != splitQueryV2Algorithm {
f.t.Errorf("invalid SplitQuery.algorithm: got %v expected %v",
algorithm, splitQueryV2Algorithm)
}
return splitQueryQueryV2SplitList, nil
}
var splitQueryBoundQuery = querytypes.BoundQuery{
Sql: "splitQuery",
BindVariables: map[string]interface{}{
@ -658,6 +704,32 @@ var splitQueryQuerySplitList = []querytypes.QuerySplit{
},
}
// TODO(erez): Rename to SplitQuery after migration to SplitQuery V2 is done.
var splitQueryV2SplitColumns = []string{"nice_column_to_split"}
const splitQueryV2SplitCount = 372
var splitQueryV2BoundQuery = querytypes.BoundQuery{
Sql: "splitQuery",
BindVariables: map[string]interface{}{
"bind1": int64(43),
},
}
const splitQueryV2NumRowsPerQueryPart = 123
const splitQueryV2Algorithm = querypb.SplitQueryRequest_FULL_SCAN
var splitQueryQueryV2SplitList = []querytypes.QuerySplit{
{
Sql: "splitQuery",
BindVariables: map[string]interface{}{
"bind1": int64(43),
"keyspace_id": int64(3333),
},
RowCount: 4456,
},
}
func testSplitQuery(t *testing.T, conn tabletconn.TabletConn) {
ctx := context.Background()
ctx = callerid.NewContext(ctx, testCallerID, testVTGateCallerID)
@ -670,6 +742,26 @@ func testSplitQuery(t *testing.T, conn tabletconn.TabletConn) {
}
}
// TODO(erez): Rename to SplitQuery after migration to SplitQuery V2 is done.
func testSplitQueryV2(t *testing.T, conn tabletconn.TabletConn) {
ctx := context.Background()
ctx = callerid.NewContext(ctx, testCallerID, testVTGateCallerID)
qsl, err := conn.SplitQueryV2(
ctx,
splitQueryV2BoundQuery,
splitQueryV2SplitColumns,
splitQueryV2SplitCount,
splitQueryV2NumRowsPerQueryPart,
splitQueryV2Algorithm,
)
if err != nil {
t.Fatalf("SplitQuery failed: %v", err)
}
if !reflect.DeepEqual(qsl, splitQueryQueryV2SplitList) {
t.Errorf("Unexpected result from SplitQuery: got %v wanted %v", qsl, splitQueryQuerySplitList)
}
}
func testSplitQueryError(t *testing.T, conn tabletconn.TabletConn) {
ctx := context.Background()
_, err := conn.SplitQuery(ctx, splitQueryBoundQuery, splitQuerySplitColumn, splitQuerySplitCount)

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

@ -23,8 +23,12 @@ import (
"github.com/youtube/vitess/go/vt/dbconfigs"
"github.com/youtube/vitess/go/vt/dbconnpool"
"github.com/youtube/vitess/go/vt/mysqlctl"
"github.com/youtube/vitess/go/vt/schema"
"github.com/youtube/vitess/go/vt/sqlparser"
"github.com/youtube/vitess/go/vt/tabletserver/queryservice"
"github.com/youtube/vitess/go/vt/tabletserver/querytypes"
"github.com/youtube/vitess/go/vt/tabletserver/splitquery"
"github.com/youtube/vitess/go/vt/utils"
"golang.org/x/net/context"
querypb "github.com/youtube/vitess/go/vt/proto/query"
@ -662,6 +666,10 @@ func (tsv *TabletServer) handleExecErrorNoPanic(sql string, bindVariables map[st
return myError
case ErrFatal:
logMethod = log.Errorf
case ErrFail:
// ErrFail is when we think the query itself is problematic. This doesn't
// indicate a system or component wide degradation, so we log to INFO.
logMethod = log.Infof
}
// We want to suppress/demote some MySQL error codes (regardless of the ErrorType)
switch terr.SQLError {
@ -797,6 +805,8 @@ func (tsv *TabletServer) ExecuteBatch(ctx context.Context, target *querypb.Targe
// SplitQuery splits a query + bind variables into smaller queries that return a
// subset of rows from the original query.
// TODO(erez): Remove this method and rename SplitQueryV2 to SplitQuery once we migrate to
// SplitQuery V2.
func (tsv *TabletServer) SplitQuery(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]interface{}, splitColumn string, splitCount int64, sessionID int64) (splits []querytypes.QuerySplit, err error) {
logStats := newLogStats("SplitQuery", ctx)
logStats.OriginalSQL = sql
@ -844,6 +854,204 @@ func (tsv *TabletServer) SplitQuery(ctx context.Context, target *querypb.Target,
return splits, nil
}
// SplitQueryV2 splits a query + bind variables into smaller queries that return a
// subset of rows from the original query. This is the new version that supports multiple
// split columns and multiple split algortihms.
// See the documentation of SplitQueryRequest in proto/vtgate.proto for more details.
func (tsv *TabletServer) SplitQueryV2(
ctx context.Context,
target *querypb.Target,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
sessionID int64) (splits []querytypes.QuerySplit, err error) {
if err := validateSplitQueryParameters(
sql,
bindVariables,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm,
sessionID); err != nil {
return nil, err
}
// TODO(erez): ASSERT/Check that we are a rdonly tablet.
logStats := newLogStats("SplitQuery", ctx)
logStats.OriginalSQL = sql
logStats.BindVariables = bindVariables
defer handleError(&err, logStats, tsv.qe.queryServiceStats)
if err = tsv.startRequest(target, sessionID, false, false); err != nil {
return nil, err
}
ctx, cancel := withTimeout(ctx, tsv.QueryTimeout.Get())
defer func() {
cancel()
tsv.endRequest(false)
}()
schema := getSchemaForSplitQuery(tsv.qe.schemaInfo)
var splitParams *splitquery.SplitParams
switch {
case numRowsPerQueryPart != 0 && splitCount == 0:
splitParams, err = splitquery.NewSplitParamsGivenNumRowsPerQueryPart(
sql, bindVariables, splitColumns, numRowsPerQueryPart, schema)
case numRowsPerQueryPart == 0 && splitCount != 0:
splitParams, err = splitquery.NewSplitParamsGivenSplitCount(
sql, bindVariables, splitColumns, splitCount, schema)
default:
panic(fmt.Sprintf("Exactly one of {numRowsPerQueryPart, splitCount} must be"+
" non zero. This should have already been caught by 'validateSplitQueryParameters' and "+
" returned as an error. Got: numRowsPerQueryPart=%v, splitCount=%v. SQL: %v",
numRowsPerQueryPart,
splitCount,
querytypes.QueryAsString(sql, bindVariables)))
}
// TODO(erez): Make the splitquery package return tabletserver errors.
if err != nil {
return nil, err
}
defer func(start time.Time) {
addUserTableQueryStats(
tsv.qe.queryServiceStats,
ctx,
splitParams.GetSplitTableName(),
"SplitQuery",
int64(time.Now().Sub(start)))
}(time.Now())
sqlExecuter := &splitQuerySQLExecuter{
queryExecutor: &QueryExecutor{
ctx: ctx,
logStats: logStats,
qe: tsv.qe,
},
}
algorithmObject, err := createSplitQueryAlgorithmObject(algorithm, splitParams, sqlExecuter)
if err != nil {
return nil, err
}
// TODO(erez): Make the splitquery package use Vitess error codes.
return splitquery.NewSplitter(splitParams, algorithmObject).Split()
}
// validateSplitQueryParameters perform some validations on the SplitQuery parameters
// returns an error that can be returned to the user if a validation fails.
func validateSplitQueryParameters(
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
sessionID int64) error {
if numRowsPerQueryPart < 0 {
return NewTabletError(
ErrFail,
vtrpcpb.ErrorCode_BAD_INPUT,
"splitQuery: numRowsPerQueryPart must be non-negative. Got: %v. SQL: %v",
numRowsPerQueryPart,
querytypes.QueryAsString(sql, bindVariables))
}
if splitCount < 0 {
return NewTabletError(
ErrFail,
vtrpcpb.ErrorCode_BAD_INPUT,
"splitQuery: splitCount must be non-negative. Got: %v. SQL: %v",
splitCount,
querytypes.QueryAsString(sql, bindVariables))
}
if (splitCount == 0 && numRowsPerQueryPart == 0) ||
(splitCount != 0 && numRowsPerQueryPart != 0) {
return NewTabletError(
ErrFail,
vtrpcpb.ErrorCode_BAD_INPUT,
"splitQuery: exactly one of {numRowsPerQueryPart, splitCount} must be"+
" non zero. Got: numRowsPerQueryPart=%v, splitCount=%v. SQL: %v",
splitCount,
querytypes.QueryAsString(sql, bindVariables))
}
if algorithm != querypb.SplitQueryRequest_EQUAL_SPLITS &&
algorithm != querypb.SplitQueryRequest_FULL_SCAN {
return NewTabletError(
ErrFail,
vtrpcpb.ErrorCode_BAD_INPUT,
"splitquery: unsupported algorithm: %v. SQL: %v",
algorithm,
querytypes.QueryAsString(sql, bindVariables))
}
return nil
}
// splitQuerySQLExecuter implements splitquery.SQLExecuterInterface and allows the splitquery
// package to send SQL statements to MySQL
// TODO(erez): Find out what's the correct way of doing this.
// We need to parse the query since we're dealing with bind-vars.
type splitQuerySQLExecuter struct {
queryExecutor *QueryExecutor
}
// TODO(erez): Add an SQLExecute() to SQLExecuterInterface that gets a parsed query so that
// we don't have to parse the query again here.
func (se *splitQuerySQLExecuter) SQLExecute(
sql string, bindVariables map[string]interface{}) (*sqltypes.Result, error) {
ast, err := sqlparser.Parse(sql)
if err != nil {
return nil, fmt.Errorf("splitQuerySQLExecuter: parsing sql failed with: %v", err)
}
parsedQuery := sqlparser.GenerateParsedQuery(ast)
conn, err := se.queryExecutor.getConn(se.queryExecutor.qe.connPool)
if err != nil {
return nil, err
}
defer conn.Recycle()
// TODO(erez): Find out what 'buildStreamComment' is, and see if we need to use it or comment why
// we don't.
// We clone "bindVariables" since fullFetch() changes it.
return se.queryExecutor.fullFetch(
conn,
parsedQuery,
utils.CloneBindVariables(bindVariables),
nil /* buildStreamComment */)
}
// getSchemaForSplitQuery converts the given schemaInfo object into
// the datastructure needed by the splitquery package: a map from a table name
// to its corresponding schame.Table object.
func getSchemaForSplitQuery(schemaInfo *SchemaInfo) map[string]*schema.Table {
// Get a snapshot of the schema.
var tableList []*schema.Table = schemaInfo.GetSchema()
result := make(map[string]*schema.Table, len(tableList))
for _, table := range tableList {
// TODO(erez): Panic if table.Name is already in 'result'.
result[table.Name] = table
}
return result
}
func createSplitQueryAlgorithmObject(
algorithm querypb.SplitQueryRequest_Algorithm,
splitParams *splitquery.SplitParams,
sqlExecuter splitquery.SQLExecuter) (splitquery.SplitAlgorithmInterface, error) {
switch algorithm {
case querypb.SplitQueryRequest_FULL_SCAN:
return splitquery.NewFullScanAlgorithm(splitParams, sqlExecuter)
case querypb.SplitQueryRequest_EQUAL_SPLITS:
return splitquery.NewEqualSplitsAlgorithm(splitParams, sqlExecuter)
default:
panic(fmt.Sprintf("Unknown algorithm enum: %+v", algorithm))
}
}
// StreamHealthRegister is part of queryservice.QueryService interface
func (tsv *TabletServer) StreamHealthRegister(c chan<- *querypb.StreamHealthResponse) (int, error) {
tsv.streamHealthMutex.Lock()

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

@ -1042,6 +1042,51 @@ func TestTabletServerSplitQuery(t *testing.T) {
}
}
// TODO(erez): Rename to TestTabletServerSplitQuery once migration to SplitQuery is done.
func TestTabletServerSplitQueryV2(t *testing.T) {
db := setUpTabletServerTest()
db.AddQuery("SELECT MIN(pk), MAX(pk) FROM test_table", &sqltypes.Result{
Fields: []*querypb.Field{
{Name: "pk", Type: sqltypes.Int32},
},
RowsAffected: 1,
Rows: [][]sqltypes.Value{
{
sqltypes.MakeTrusted(sqltypes.Int32, []byte("1")),
sqltypes.MakeTrusted(sqltypes.Int32, []byte("100")),
},
},
})
testUtils := newTestUtils()
config := testUtils.newQueryServiceConfig()
tsv := NewTabletServer(config)
dbconfigs := testUtils.newDBConfigs(db)
target := querypb.Target{TabletType: topodatapb.TabletType_MASTER}
err := tsv.StartService(target, dbconfigs, []SchemaOverride{}, testUtils.newMysqld(&dbconfigs))
if err != nil {
t.Fatalf("StartService failed: %v", err)
}
defer tsv.StopService()
ctx := context.Background()
sql := "select * from test_table where count > :count"
splits, err := tsv.SplitQueryV2(
ctx,
nil, /* target */
sql,
nil, /* bindVariables */
[]string{}, /* splitColumns */
10, /* splitCount */
0, /* numRowsPerQueryPart */
querypb.SplitQueryRequest_EQUAL_SPLITS,
tsv.sessionID)
if err != nil {
t.Fatalf("TabletServer.SplitQuery should succeed: %v, but get error: %v", sql, err)
}
if len(splits) != 10 {
t.Fatalf("got: %v, want: %v.\nsplits: %+v", len(splits), 10, splits)
}
}
func TestTabletServerSplitQueryInvalidQuery(t *testing.T) {
db := setUpTabletServerTest()
db.AddQuery("SELECT MIN(pk), MAX(pk) FROM test_table", &sqltypes.Result{
@ -1084,7 +1129,40 @@ func TestTabletServerSplitQueryInvalidQuery(t *testing.T) {
}
}
// TODO(erez): Rename to TestTabletServerSplitQueryInvalidQuery once migration to SplitQuery
// is done.
func TestTabletServerSplitQueryV2InvalidQuery(t *testing.T) {
db := setUpTabletServerTest()
testUtils := newTestUtils()
config := testUtils.newQueryServiceConfig()
tsv := NewTabletServer(config)
dbconfigs := testUtils.newDBConfigs(db)
target := querypb.Target{TabletType: topodatapb.TabletType_MASTER}
err := tsv.StartService(target, dbconfigs, []SchemaOverride{}, testUtils.newMysqld(&dbconfigs))
if err != nil {
t.Fatalf("StartService failed: %v", err)
}
defer tsv.StopService()
ctx := context.Background()
// SplitQuery should not support SQLs with a LIMIT clause:
sql := "select * from test_table where count > :count limit 10"
_, err = tsv.SplitQueryV2(
ctx,
nil, /* target */
sql,
nil, /* bindVariables */
[]string{}, /* splitColumns */
10, /* splitCount */
0, /* numRowsPerQueryPart */
querypb.SplitQueryRequest_EQUAL_SPLITS,
tsv.sessionID)
if err == nil {
t.Fatalf("TabletServer.SplitQuery should fail")
}
}
func TestTabletServerSplitQueryInvalidMinMax(t *testing.T) {
// Tests that split query returns an error when the query is invalid.
db := setUpTabletServerTest()
testUtils := newTestUtils()
pkMinMaxQuery := "SELECT MIN(pk), MAX(pk) FROM test_table"
@ -1129,6 +1207,38 @@ func TestTabletServerSplitQueryInvalidMinMax(t *testing.T) {
}
}
// TODO(erez): Rename to TestTabletServerSplitQueryInvalidParams once migration to SplitQuery
// is done.
func TestTabletServerSplitQueryV2InvalidParams(t *testing.T) {
// Tests that SplitQuery returns an error when both numRowsPerQueryPart and splitCount are given.
db := setUpTabletServerTest()
testUtils := newTestUtils()
config := testUtils.newQueryServiceConfig()
tsv := NewTabletServer(config)
dbconfigs := testUtils.newDBConfigs(db)
target := querypb.Target{TabletType: topodatapb.TabletType_MASTER}
err := tsv.StartService(target, dbconfigs, []SchemaOverride{}, testUtils.newMysqld(&dbconfigs))
if err != nil {
t.Fatalf("StartService failed: %v", err)
}
defer tsv.StopService()
ctx := context.Background()
sql := "select * from test_table where count > :count"
_, err = tsv.SplitQueryV2(
ctx,
nil, /* target */
sql,
nil, /* bindVariables */
[]string{}, /* splitColumns */
10, /* splitCount */
11, /* numRowsPerQueryPart */
querypb.SplitQueryRequest_EQUAL_SPLITS,
tsv.sessionID)
if err == nil {
t.Fatalf("TabletServer.SplitQuery should fail")
}
}
func TestHandleExecUnknownError(t *testing.T) {
ctx := context.Background()
logStats := newLogStats("TestHandleExecError", ctx)

12
go/vt/utils/utils.go Normal file
Просмотреть файл

@ -0,0 +1,12 @@
package utils
// utils.go contains general utility functions used in the splitquery package.
// cloneBindVariables returns a shallow-copy of the given bindVariables map.
func CloneBindVariables(bindVariables map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{}, len(bindVariables))
for key, value := range bindVariables {
result[key] = value
}
return result
}

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

@ -22,6 +22,7 @@ type fakeVTGateService struct {
type queryExecute struct {
SQL string
BindVariables map[string]interface{}
Keyspace string
TabletType topodatapb.TabletType
Session *vtgatepb.Session
NotInTransaction bool
@ -36,7 +37,7 @@ type queryExecuteSpecificShard struct {
}
// Execute is part of the VTGateService interface
func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
execCase, ok := execMap[sql]
if !ok {
return nil, fmt.Errorf("no match for: %s", sql)
@ -44,6 +45,7 @@ func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariabl
query := &queryExecute{
SQL: sql,
BindVariables: bindVariables,
Keyspace: keyspace,
TabletType: tabletType,
Session: session,
NotInTransaction: notInTransaction,
@ -109,7 +111,7 @@ func (f *fakeVTGateService) ExecuteBatchKeyspaceIds(ctx context.Context, queries
}
// StreamExecute is part of the VTGateService interface
func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
execCase, ok := execMap[sql]
if !ok {
return fmt.Errorf("no match for: %s", sql)
@ -117,6 +119,7 @@ func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindV
query := &queryExecute{
SQL: sql,
BindVariables: bindVariables,
Keyspace: keyspace,
TabletType: tabletType,
}
if !reflect.DeepEqual(query, execCase.execQuery) {
@ -214,6 +217,21 @@ func (f *fakeVTGateService) SplitQuery(ctx context.Context, keyspace string, sql
return nil, nil
}
// SplitQueryV2 is part of the VTGateService interface
// TODO(erez): Rename to SplitQuery after migration to SplitQuery V2 is done.
func (f *fakeVTGateService) SplitQueryV2(
ctx context.Context,
keyspace string,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
) ([]*vtgatepb.SplitQueryResponse_Part, error) {
return nil, nil
}
// GetSrvKeyspace is part of the VTGateService interface
func (f *fakeVTGateService) GetSrvKeyspace(ctx context.Context, keyspace string) (*topodatapb.SrvKeyspace, error) {
return &topodatapb.SrvKeyspace{}, nil

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

@ -23,6 +23,7 @@ import (
"github.com/youtube/vitess/go/vt/vterrors"
"github.com/youtube/vitess/go/vt/vtgate/txbuffer"
querypb "github.com/youtube/vitess/go/vt/proto/query"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
vtrpcpb "github.com/youtube/vitess/go/vt/proto/vtrpc"
)
@ -142,7 +143,9 @@ func (dg *discoveryGateway) Begin(ctx context.Context, keyspace string, shard st
err = dg.withRetry(ctx, keyspace, shard, tabletType, func(conn tabletconn.TabletConn) error {
var innerErr error
// Potentially buffer this transaction.
txbuffer.FakeBuffer(keyspace, shard, attemptNumber)
if bufferErr := txbuffer.FakeBuffer(keyspace, shard, attemptNumber); bufferErr != nil {
return bufferErr
}
transactionID, innerErr = conn.Begin(ctx)
attemptNumber++
return innerErr
@ -177,6 +180,31 @@ func (dg *discoveryGateway) SplitQuery(ctx context.Context, keyspace, shard stri
return
}
// SplitQuery splits a query into sub-queries for the specified keyspace, shard, and tablet type.
// TODO(erez): Rename to SplitQuery after migration to SplitQuery V2.
func (dg *discoveryGateway) SplitQueryV2(
ctx context.Context,
keyspace,
shard string,
tabletType topodatapb.TabletType,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) (queries []querytypes.QuerySplit, err error) {
err = dg.withRetry(ctx, keyspace, shard, tabletType, func(conn tabletconn.TabletConn) error {
var innerErr error
queries, innerErr = conn.SplitQueryV2(ctx, querytypes.BoundQuery{
Sql: sql,
BindVariables: bindVariables,
}, splitColumns, splitCount, numRowsPerQueryPart, algorithm)
return innerErr
}, 0, false)
return
}
// Close shuts down underlying connections.
func (dg *discoveryGateway) Close(ctx context.Context) error {
for _, ctw := range dg.tabletsWatchers {

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

@ -62,16 +62,36 @@ type querySplitQuery struct {
SplitCount int64
}
// TODO(erez): Rename after migration to SplitQuery V2 is done.
type querySplitQueryV2 struct {
Keyspace string
SQL string
BindVariables map[string]interface{}
SplitColumns []string
SplitCount int64
NumRowsPerQueryPart int64
Algorithm querypb.SplitQueryRequest_Algorithm
}
type splitQueryResponse struct {
splitQuery *querySplitQuery
reply []*vtgatepb.SplitQueryResponse_Part
err error
}
// TODO(erez): Rename after migration to SplitQuery V2 is done.
type splitQueryV2Response struct {
splitQuery *querySplitQueryV2
reply []*vtgatepb.SplitQueryResponse_Part
err error
}
// FakeVTGateConn provides a fake implementation of vtgateconn.Impl
type FakeVTGateConn struct {
execMap map[string]*queryResponse
splitQueryMap map[string]*splitQueryResponse
// TODO(erez): Rename after migration to SplitQuery V2 is done.
splitQueryV2Map map[string]*splitQueryV2Response
}
// RegisterFakeVTGateConnDialer registers the proper dialer for this fake,
@ -80,8 +100,9 @@ type FakeVTGateConn struct {
func RegisterFakeVTGateConnDialer() (*FakeVTGateConn, string) {
protocol := "fake"
impl := &FakeVTGateConn{
execMap: make(map[string]*queryResponse),
splitQueryMap: make(map[string]*splitQueryResponse),
execMap: make(map[string]*queryResponse),
splitQueryMap: make(map[string]*splitQueryResponse),
splitQueryV2Map: make(map[string]*splitQueryV2Response),
}
vtgateconn.RegisterDialer(protocol, func(ctx context.Context, address string, timeout time.Duration) (vtgateconn.Impl, error) {
return impl, nil
@ -141,6 +162,7 @@ func (conn *FakeVTGateConn) AddSplitQuery(
splitColumn string,
splitCount int64,
expectedResult []*vtgatepb.SplitQueryResponse_Part) {
reply := make([]*vtgatepb.SplitQueryResponse_Part, splitCount)
copy(reply, expectedResult)
key := getSplitQueryKey(keyspace, sql, splitColumn, splitCount)
@ -157,6 +179,36 @@ func (conn *FakeVTGateConn) AddSplitQuery(
}
}
// AddSplitQueryV2 adds a split query and expected result.
// TODO(erez): Rename after migration to SplitQuery V2 is done.
func (conn *FakeVTGateConn) AddSplitQueryV2(
keyspace string,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
expectedResult []*vtgatepb.SplitQueryResponse_Part) {
reply := make([]*vtgatepb.SplitQueryResponse_Part, len(expectedResult))
copy(reply, expectedResult)
key := getSplitQueryV2Key(keyspace, sql, splitColumns, splitCount, numRowsPerQueryPart, algorithm)
conn.splitQueryV2Map[key] = &splitQueryV2Response{
splitQuery: &querySplitQueryV2{
Keyspace: keyspace,
SQL: sql,
BindVariables: bindVariables,
SplitColumns: splitColumns,
SplitCount: splitCount,
NumRowsPerQueryPart: numRowsPerQueryPart,
Algorithm: algorithm,
},
reply: reply,
err: nil,
}
}
// Execute please see vtgateconn.Impl.Execute
func (conn *FakeVTGateConn) Execute(ctx context.Context, sql string, bindVars map[string]interface{}, tabletType topodatapb.TabletType, session interface{}) (*sqltypes.Result, interface{}, error) {
var s *vtgatepb.Session
@ -352,7 +404,36 @@ func (conn *FakeVTGateConn) SplitQuery(ctx context.Context, keyspace string, que
return reply, nil
}
// GetSrvKeyspace please see vtgateconn.Impl.SplitQuery
// SplitQueryV2 please see vtgateconn.Impl.SplitQueryV2
// TODO(erez): Rename after migration to SplitQuery V2 is done.
func (conn *FakeVTGateConn) SplitQueryV2(
ctx context.Context,
keyspace string,
query string,
bindVars map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]*vtgatepb.SplitQueryResponse_Part, error) {
response, ok := conn.splitQueryV2Map[getSplitQueryV2Key(
keyspace, query, splitColumns, splitCount, numRowsPerQueryPart, algorithm)]
if !ok {
return nil, fmt.Errorf(
"no match for keyspace: %s,"+
" query: %v,"+
" splitColumns: %v,"+
" splitCount: %v"+
" numRowsPerQueryPart: %v"+
" algorithm: %v",
keyspace, query, splitColumns, splitCount, numRowsPerQueryPart, algorithm)
}
reply := make([]*vtgatepb.SplitQueryResponse_Part, len(response.reply))
copy(reply, response.reply)
return reply, nil
}
// GetSrvKeyspace please see vtgateconn.Impl.GetSrvKeyspace
func (conn *FakeVTGateConn) GetSrvKeyspace(ctx context.Context, keyspace string) (*topodatapb.SrvKeyspace, error) {
return nil, fmt.Errorf("NYI")
}
@ -370,6 +451,24 @@ func getSplitQueryKey(keyspace string, query string, splitColumn string, splitCo
return fmt.Sprintf("%s:%v:%v:%d", keyspace, query, splitColumn, splitCount)
}
// TODO(erez): Rename after migration to SplitQuery V2 is done.
func getSplitQueryV2Key(
keyspace string,
query string,
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) string {
return fmt.Sprintf(
"%v:%v:%v:%v:%v:%v",
keyspace,
query,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm)
}
func newSession(
inTransaction bool,
keyspace string,

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

@ -19,6 +19,7 @@ import (
"github.com/youtube/vitess/go/vt/tabletserver/querytypes"
"github.com/youtube/vitess/go/vt/topo"
querypb "github.com/youtube/vitess/go/vt/proto/query"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)
@ -55,6 +56,20 @@ type Gateway interface {
// SplitQuery splits a query into sub-queries for the specified keyspace, shard, and tablet type.
SplitQuery(ctx context.Context, keyspace, shard string, tabletType topodatapb.TabletType, sql string, bindVariables map[string]interface{}, splitColumn string, splitCount int64) ([]querytypes.QuerySplit, error)
// SplitQuery splits a query into sub-queries for the specified keyspace, shard, and tablet type.
// TODO(erez): Rename to SplitQuery after migration to SplitQuery V2.
SplitQueryV2(
ctx context.Context,
keyspace,
shard string,
tabletType topodatapb.TabletType,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]querytypes.QuerySplit, error)
// Close shuts down underlying connections.
Close(ctx context.Context) error
@ -128,22 +143,60 @@ type GatewayEndPointCacheStatus struct {
AvgLatency float64 // in milliseconds
}
const (
aggrChanSize = 10000
)
var (
// aggrChan buffers queryInfo objects to be processed.
aggrChan chan *queryInfo
// muAggr protects below vars.
muAggr sync.Mutex
// aggregators holds all Aggregators created.
aggregators []*GatewayEndPointStatusAggregator
// gatewayStatsChanFull tracks the number of times
// aggrChan becomes full.
gatewayStatsChanFull *stats.Int
)
func init() {
// init global goroutines to aggregate stats.
aggrChan = make(chan *queryInfo, aggrChanSize)
gatewayStatsChanFull = stats.NewInt("GatewayStatsChanFullCount")
go resetAggregators()
go processQueryInfo()
}
// registerAggregator registers an aggregator to the global list.
func registerAggregator(a *GatewayEndPointStatusAggregator) {
muAggr.Lock()
defer muAggr.Unlock()
aggregators = append(aggregators, a)
}
// resetAggregators resets the next stats slot for all aggregators every second.
func resetAggregators() {
ticker := time.NewTicker(time.Second)
for range ticker.C {
muAggr.Lock()
for _, a := range aggregators {
a.resetNextSlot()
}
muAggr.Unlock()
}
}
// processQueryInfo processes the next queryInfo object.
func processQueryInfo() {
for qi := range aggrChan {
qi.aggr.processQueryInfo(qi)
}
}
// NewGatewayEndPointStatusAggregator creates a GatewayEndPointStatusAggregator.
func NewGatewayEndPointStatusAggregator() *GatewayEndPointStatusAggregator {
gepsa := &GatewayEndPointStatusAggregator{
qiChan: make(chan *queryInfo, 10000),
}
go func() {
ticker := time.NewTicker(time.Second)
for range ticker.C {
gepsa.resetNextSlot()
}
}()
go func() {
for qi := range gepsa.qiChan {
gepsa.processQueryInfo(qi)
}
}()
gepsa := &GatewayEndPointStatusAggregator{}
registerAggregator(gepsa)
return gepsa
}
@ -154,7 +207,6 @@ type GatewayEndPointStatusAggregator struct {
TabletType topodatapb.TabletType
Name string // the alternative name of an endpoint
Addr string // the host:port of an endpoint
qiChan chan *queryInfo
// mu protects below fields.
mu sync.RWMutex
@ -167,6 +219,7 @@ type GatewayEndPointStatusAggregator struct {
}
type queryInfo struct {
aggr *GatewayEndPointStatusAggregator
addr string
tabletType topodatapb.TabletType
elapsed time.Duration
@ -176,20 +229,24 @@ type queryInfo struct {
// UpdateQueryInfo updates the aggregator with the given information about a query.
func (gepsa *GatewayEndPointStatusAggregator) UpdateQueryInfo(addr string, tabletType topodatapb.TabletType, elapsed time.Duration, hasError bool) {
qi := &queryInfo{
aggr: gepsa,
addr: addr,
tabletType: tabletType,
elapsed: elapsed,
hasError: hasError,
}
select {
case gepsa.qiChan <- qi:
case aggrChan <- qi:
default:
gatewayStatsChanFull.Add(1)
}
}
func (gepsa *GatewayEndPointStatusAggregator) processQueryInfo(qi *queryInfo) {
gepsa.mu.Lock()
defer gepsa.mu.Unlock()
if gepsa.TabletType != qi.tabletType {
gepsa.TabletType = qi.tabletType
// reset counters
gepsa.QueryCount = 0
gepsa.QueryError = 0
@ -203,14 +260,12 @@ func (gepsa *GatewayEndPointStatusAggregator) processQueryInfo(qi *queryInfo) {
if qi.addr != "" {
gepsa.Addr = qi.addr
}
gepsa.TabletType = qi.tabletType
gepsa.QueryCount++
gepsa.queryCountInMinute[gepsa.tick]++
gepsa.latencyInMinute[gepsa.tick] += qi.elapsed
if qi.hasError {
gepsa.QueryError++
}
gepsa.mu.Unlock()
}
// GetCacheStatus returns a GatewayEndPointCacheStatus representing the current gateway status.

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

@ -19,20 +19,37 @@ func TestGatwayEndPointStatusAggregator(t *testing.T) {
TabletType: topodatapb.TabletType_REPLICA,
Name: "n",
Addr: "a",
qiChan: make(chan *queryInfo, 10000),
}
t.Logf("aggr = GatwayEndPointStatusAggregator{k, s, replica, n, a}")
aggr.UpdateQueryInfo("", topodatapb.TabletType_REPLICA, 10*time.Millisecond, false)
aggr.processQueryInfo(<-aggr.qiChan)
t.Logf("aggr.UpdateQueryInfo(, replica, 10ms, false)")
qi := &queryInfo{
aggr: aggr,
addr: "",
tabletType: topodatapb.TabletType_REPLICA,
elapsed: 10 * time.Millisecond,
hasError: false,
}
aggr.processQueryInfo(qi)
t.Logf("aggr.processQueryInfo(, replica, 10ms, false)")
aggr.resetNextSlot()
t.Logf("aggr.resetNextSlot()")
aggr.UpdateQueryInfo("", topodatapb.TabletType_REPLICA, 8*time.Millisecond, false)
aggr.processQueryInfo(<-aggr.qiChan)
t.Logf("aggr.UpdateQueryInfo(, replica, 8ms, false)")
aggr.UpdateQueryInfo("", topodatapb.TabletType_REPLICA, 3*time.Millisecond, true)
aggr.processQueryInfo(<-aggr.qiChan)
t.Logf("aggr.UpdateQueryInfo(, replica, 3ms, true)")
qi = &queryInfo{
aggr: aggr,
addr: "",
tabletType: topodatapb.TabletType_REPLICA,
elapsed: 8 * time.Millisecond,
hasError: false,
}
aggr.processQueryInfo(qi)
t.Logf("aggr.processQueryInfo(, replica, 8ms, false)")
qi = &queryInfo{
aggr: aggr,
addr: "",
tabletType: topodatapb.TabletType_REPLICA,
elapsed: 3 * time.Millisecond,
hasError: true,
}
aggr.processQueryInfo(qi)
t.Logf("aggr.processQueryInfo(, replica, 3ms, true)")
want := &GatewayEndPointCacheStatus{
Keyspace: "k",
Shard: "s",
@ -53,12 +70,24 @@ func TestGatwayEndPointStatusAggregator(t *testing.T) {
aggr.resetNextSlot()
}
t.Logf("59 aggr.resetNextSlot()")
aggr.UpdateQueryInfo("b", topodatapb.TabletType_MASTER, 9*time.Millisecond, false)
aggr.processQueryInfo(<-aggr.qiChan)
t.Logf("aggr.UpdateQueryInfo(b, master, 9ms, false)")
aggr.UpdateQueryInfo("", topodatapb.TabletType_MASTER, 6*time.Millisecond, true)
aggr.processQueryInfo(<-aggr.qiChan)
t.Logf("aggr.UpdateQueryInfo(, master, 6ms, true)")
qi = &queryInfo{
aggr: aggr,
addr: "b",
tabletType: topodatapb.TabletType_MASTER,
elapsed: 9 * time.Millisecond,
hasError: false,
}
aggr.processQueryInfo(qi)
t.Logf("aggr.processQueryInfo(b, master, 9ms, false)")
qi = &queryInfo{
aggr: aggr,
addr: "",
tabletType: topodatapb.TabletType_MASTER,
elapsed: 6 * time.Millisecond,
hasError: true,
}
aggr.processQueryInfo(qi)
t.Logf("aggr.processQueryInfo(, master, 6ms, true)")
want = &GatewayEndPointCacheStatus{
Keyspace: "k",
Shard: "s",

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

@ -396,11 +396,45 @@ func (conn *vtgateConn) SplitQuery(ctx context.Context, keyspace string, query s
}
request := &vtgatepb.SplitQueryRequest{
CallerId: callerid.EffectiveCallerIDFromContext(ctx),
Keyspace: keyspace,
Query: q,
SplitColumn: splitColumn,
SplitCount: splitCount,
CallerId: callerid.EffectiveCallerIDFromContext(ctx),
Keyspace: keyspace,
Query: q,
SplitColumn: []string{splitColumn},
SplitCount: splitCount,
NumRowsPerQueryPart: 0,
Algorithm: querypb.SplitQueryRequest_EQUAL_SPLITS,
UseSplitQueryV2: false,
}
response, err := conn.c.SplitQuery(ctx, request)
if err != nil {
return nil, vterrors.FromGRPCError(err)
}
return response.Splits, nil
}
func (conn *vtgateConn) SplitQueryV2(
ctx context.Context,
keyspace string,
query string,
bindVars map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]*vtgatepb.SplitQueryResponse_Part, error) {
q, err := querytypes.BoundQueryToProto3(query, bindVars)
if err != nil {
return nil, err
}
request := &vtgatepb.SplitQueryRequest{
CallerId: callerid.EffectiveCallerIDFromContext(ctx),
Keyspace: keyspace,
Query: q,
SplitColumn: splitColumns,
SplitCount: splitCount,
NumRowsPerQueryPart: numRowsPerQueryPart,
Algorithm: algorithm,
UseSplitQueryV2: true,
}
response, err := conn.c.SplitQuery(ctx, request)
if err != nil {

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

@ -37,7 +37,7 @@ func (vtg *VTGate) Execute(ctx context.Context, request *vtgatepb.ExecuteRequest
if err != nil {
return nil, vterrors.ToGRPCError(err)
}
result, err := vtg.server.Execute(ctx, string(request.Query.Sql), bv, request.TabletType, request.Session, request.NotInTransaction)
result, err := vtg.server.Execute(ctx, string(request.Query.Sql), bv, request.Keyspace, request.TabletType, request.Session, request.NotInTransaction)
return &vtgatepb.ExecuteResponse{
Result: sqltypes.ResultToProto3(result),
Session: request.Session,
@ -196,6 +196,7 @@ func (vtg *VTGate) StreamExecute(request *vtgatepb.StreamExecuteRequest, stream
vtgErr := vtg.server.StreamExecute(ctx,
string(request.Query.Sql),
bv,
request.Keyspace,
request.TabletType,
func(value *sqltypes.Result) error {
return stream.Send(&vtgatepb.StreamExecuteResponse{
@ -333,12 +334,17 @@ func (vtg *VTGate) SplitQuery(ctx context.Context, request *vtgatepb.SplitQueryR
if err != nil {
return nil, vterrors.ToGRPCError(err)
}
splits, vtgErr := vtg.server.SplitQuery(ctx,
splits, vtgErr := vtgateservice.CallCorrectSplitQuery(
vtg.server,
request.UseSplitQueryV2,
ctx,
request.Keyspace,
string(request.Query.Sql),
bv,
request.SplitColumn,
request.SplitCount)
request.SplitCount,
request.NumRowsPerQueryPart,
request.Algorithm)
if vtgErr != nil {
return nil, vterrors.ToGRPCError(vtgErr)
}

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

@ -68,9 +68,15 @@ type builder interface {
SupplyCol(ref colref) int
}
// VSchema defines the interface for this package to fetch
// info about tables.
type VSchema interface {
Find(keyspace, tablename string) (table *vindexes.Table, err error)
}
// Build builds a plan for a query based on the specified vschema.
// It's the main entry point for this package.
func Build(query string, vschema *vindexes.VSchema) (*engine.Plan, error) {
func Build(query string, vschema VSchema) (*engine.Plan, error) {
statement, err := sqlparser.Parse(query)
if err != nil {
return nil, err

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

@ -14,15 +14,23 @@ import (
"github.com/youtube/vitess/go/vt/vtgate/vindexes"
)
// dmlFormatter strips out keyspace name from dmls.
func dmlFormatter(buf *sqlparser.TrackedBuffer, node sqlparser.SQLNode) {
switch node := node.(type) {
case *sqlparser.TableName:
node.Name.Format(buf)
return
}
node.Format(buf)
}
// buildUpdatePlan builds the instructions for an UPDATE statement.
func buildUpdatePlan(upd *sqlparser.Update, vschema *vindexes.VSchema) (*engine.Route, error) {
func buildUpdatePlan(upd *sqlparser.Update, vschema VSchema) (*engine.Route, error) {
route := &engine.Route{
Query: generateQuery(upd),
}
// We allow only one table in an update.
tablename := sqlparser.GetTableName(upd.Table)
var err error
route.Table, err = vschema.FindTable(tablename)
route.Table, err = vschema.Find(string(upd.Table.Qualifier), string(upd.Table.Name))
if err != nil {
return nil, err
}
@ -47,7 +55,7 @@ func buildUpdatePlan(upd *sqlparser.Update, vschema *vindexes.VSchema) (*engine.
}
func generateQuery(statement sqlparser.Statement) string {
buf := sqlparser.NewTrackedBuffer(nil)
buf := sqlparser.NewTrackedBuffer(dmlFormatter)
statement.Format(buf)
return buf.String()
}
@ -68,14 +76,12 @@ func isIndexChanging(setClauses sqlparser.UpdateExprs, colVindexes []*vindexes.C
}
// buildUpdatePlan builds the instructions for a DELETE statement.
func buildDeletePlan(del *sqlparser.Delete, vschema *vindexes.VSchema) (*engine.Route, error) {
func buildDeletePlan(del *sqlparser.Delete, vschema VSchema) (*engine.Route, error) {
route := &engine.Route{
Query: generateQuery(del),
}
// We allow only one table in a delete.
tablename := sqlparser.GetTableName(del.Table)
var err error
route.Table, err = vschema.FindTable(tablename)
route.Table, err = vschema.Find(string(del.Table.Qualifier), string(del.Table.Name))
if err != nil {
return nil, err
}

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

@ -13,12 +13,11 @@ import (
"github.com/youtube/vitess/go/vt/vtgate/vindexes"
)
// This file has functions to analyze the FROM clause
// for select statements.
// This file has functions to analyze the FROM clause.
// processTableExprs analyzes the FROM clause. It produces a builder
// with all the routes identified.
func processTableExprs(tableExprs sqlparser.TableExprs, vschema *vindexes.VSchema) (builder, error) {
func processTableExprs(tableExprs sqlparser.TableExprs, vschema VSchema) (builder, error) {
if len(tableExprs) != 1 {
return nil, errors.New("unsupported: ',' join operator")
}
@ -26,7 +25,7 @@ func processTableExprs(tableExprs sqlparser.TableExprs, vschema *vindexes.VSchem
}
// processTableExpr produces a builder subtree for the given TableExpr.
func processTableExpr(tableExpr sqlparser.TableExpr, vschema *vindexes.VSchema) (builder, error) {
func processTableExpr(tableExpr sqlparser.TableExpr, vschema VSchema) (builder, error) {
switch tableExpr := tableExpr.(type) {
case *sqlparser.AliasedTableExpr:
return processAliasedTable(tableExpr, vschema)
@ -55,7 +54,7 @@ func processTableExpr(tableExpr sqlparser.TableExpr, vschema *vindexes.VSchema)
// vindex columns will be added to the tabsym.
// A symtab symbol can only point to a route. This means that we canoot
// support complex joins in subqueries yet.
func processAliasedTable(tableExpr *sqlparser.AliasedTableExpr, vschema *vindexes.VSchema) (builder, error) {
func processAliasedTable(tableExpr *sqlparser.AliasedTableExpr, vschema VSchema) (builder, error) {
switch expr := tableExpr.Expr.(type) {
case *sqlparser.TableName:
eroute, table, err := getTablePlan(expr, vschema)
@ -118,8 +117,8 @@ func processAliasedTable(tableExpr *sqlparser.AliasedTableExpr, vschema *vindexe
// getTablePlan produces the initial engine.Route for the specified TableName.
// It also returns the associated vschema info (*Table) so that
// it can be used to create the symbol table entry.
func getTablePlan(tableName *sqlparser.TableName, vschema *vindexes.VSchema) (*engine.Route, *vindexes.Table, error) {
table, err := vschema.FindTable(string(tableName.Name))
func getTablePlan(tableName *sqlparser.TableName, vschema VSchema) (*engine.Route, *vindexes.Table, error) {
table, err := vschema.Find(string(tableName.Qualifier), string(tableName.Name))
if err != nil {
return nil, nil, err
}
@ -140,7 +139,7 @@ func getTablePlan(tableName *sqlparser.TableName, vschema *vindexes.VSchema) (*e
// processJoin produces a builder subtree for the given Join.
// If the left and right nodes can be part of the same route,
// then it's a route. Otherwise, it's a join.
func processJoin(ajoin *sqlparser.JoinTableExpr, vschema *vindexes.VSchema) (builder, error) {
func processJoin(ajoin *sqlparser.JoinTableExpr, vschema VSchema) (builder, error) {
switch ajoin.Join {
case sqlparser.JoinStr, sqlparser.StraightJoinStr, sqlparser.LeftJoinStr:
case sqlparser.RightJoinStr:

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

@ -14,13 +14,12 @@ import (
)
// buildInsertPlan builds the route for an INSERT statement.
func buildInsertPlan(ins *sqlparser.Insert, vschema *vindexes.VSchema) (*engine.Route, error) {
func buildInsertPlan(ins *sqlparser.Insert, vschema VSchema) (*engine.Route, error) {
route := &engine.Route{
Query: generateQuery(ins),
}
tablename := sqlparser.GetTableName(ins.Table)
var err error
route.Table, err = vschema.FindTable(tablename)
route.Table, err = vschema.Find(string(ins.Table.Qualifier), string(ins.Table.Name))
if err != nil {
return nil, err
}

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

@ -36,7 +36,7 @@ type route struct {
ERoute *engine.Route
}
func newRoute(from sqlparser.TableExprs, eroute *engine.Route, table *vindexes.Table, vschema *vindexes.VSchema, alias, astName sqlparser.SQLName) *route {
func newRoute(from sqlparser.TableExprs, eroute *engine.Route, table *vindexes.Table, vschema VSchema, alias, astName sqlparser.SQLName) *route {
// We have some circular pointer references here:
// The route points to the symtab idicating
// the symtab that should be used to resolve symbols

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

@ -13,7 +13,7 @@ import (
)
// buildSelectPlan is the new function to build a Select plan.
func buildSelectPlan(sel *sqlparser.Select, vschema *vindexes.VSchema) (primitive engine.Primitive, err error) {
func buildSelectPlan(sel *sqlparser.Select, vschema VSchema) (primitive engine.Primitive, err error) {
bindvars := getBindvars(sel)
builder, err := processSelect(sel, vschema, nil)
if err != nil {
@ -43,7 +43,7 @@ func getBindvars(node sqlparser.SQLNode) map[string]struct{} {
}
// processSelect builds a primitive tree for the given query or subquery.
func processSelect(sel *sqlparser.Select, vschema *vindexes.VSchema, outer builder) (builder, error) {
func processSelect(sel *sqlparser.Select, vschema VSchema, outer builder) (builder, error) {
bldr, err := processTableExprs(sel.From, vschema)
if err != nil {
return nil, err

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

@ -50,12 +50,12 @@ type symtab struct {
Colsyms []*colsym
Externs []*sqlparser.ColName
Outer *symtab
VSchema *vindexes.VSchema
VSchema VSchema
}
// newSymtab creates a new symtab initialized
// to contain the provided table alias.
func newSymtab(vschema *vindexes.VSchema) *symtab {
func newSymtab(vschema VSchema) *symtab {
return &symtab{
VSchema: vschema,
}

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

@ -45,14 +45,21 @@ func NewPlanner(vschema *vindexes.VSchema, cacheSize int) *Planner {
// GetPlan computes the plan for the given query. If one is in
// the cache, it reuses it.
func (plr *Planner) GetPlan(sql string) (*engine.Plan, error) {
func (plr *Planner) GetPlan(sql, keyspace string) (*engine.Plan, error) {
if plr.vschema == nil {
return nil, errors.New("vschema not initialized")
}
if result, ok := plr.plans.Get(sql); ok {
key := sql
if keyspace != "" {
key = keyspace + ":" + sql
}
if result, ok := plr.plans.Get(key); ok {
return result.(*engine.Plan), nil
}
plan, err := planbuilder.Build(sql, plr.vschema)
plan, err := planbuilder.Build(sql, &wrappedVSchema{
vschema: plr.vschema,
keyspace: keyspace,
})
if err != nil {
return nil, err
}
@ -95,3 +102,15 @@ func (plr *Planner) ServeHTTP(response http.ResponseWriter, request *http.Reques
response.WriteHeader(http.StatusNotFound)
}
}
type wrappedVSchema struct {
vschema *vindexes.VSchema
keyspace string
}
func (vs *wrappedVSchema) Find(keyspace, tablename string) (table *vindexes.Table, err error) {
if keyspace == "" {
keyspace = vs.keyspace
}
return vs.vschema.Find(keyspace, tablename)
}

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

@ -17,17 +17,19 @@ type requestContext struct {
ctx context.Context
sql string
bindVars map[string]interface{}
keyspace string
tabletType topodatapb.TabletType
session *vtgatepb.Session
notInTransaction bool
router *Router
}
func newRequestContext(ctx context.Context, sql string, bindVars map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool, router *Router) *requestContext {
func newRequestContext(ctx context.Context, sql string, bindVars map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool, router *Router) *requestContext {
return &requestContext{
ctx: ctx,
sql: sql,
bindVars: bindVars,
keyspace: keyspace,
tabletType: tabletType,
session: session,
notInTransaction: notInTransaction,
@ -36,7 +38,9 @@ func newRequestContext(ctx context.Context, sql string, bindVars map[string]inte
}
func (vc *requestContext) Execute(query string, bindvars map[string]interface{}) (*sqltypes.Result, error) {
return vc.router.Execute(vc.ctx, query, bindvars, vc.tabletType, vc.session, false)
// We have to use an empty keyspace here, becasue vindexes that call back can reference
// any table.
return vc.router.Execute(vc.ctx, query, bindvars, "", vc.tabletType, vc.session, false)
}
func (vc *requestContext) ExecuteRoute(route *engine.Route, joinvars map[string]interface{}) (*sqltypes.Result, error) {

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

@ -59,12 +59,12 @@ func NewRouter(serv topo.SrvTopoServer, cell string, vschema *vindexes.VSchema,
}
// Execute routes a non-streaming query.
func (rtr *Router) Execute(ctx context.Context, sql string, bindVars map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
func (rtr *Router) Execute(ctx context.Context, sql string, bindVars map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if bindVars == nil {
bindVars = make(map[string]interface{})
}
vcursor := newRequestContext(ctx, sql, bindVars, tabletType, session, notInTransaction, rtr)
plan, err := rtr.planner.GetPlan(sql)
vcursor := newRequestContext(ctx, sql, bindVars, keyspace, tabletType, session, notInTransaction, rtr)
plan, err := rtr.planner.GetPlan(sql, keyspace)
if err != nil {
return nil, err
}
@ -72,12 +72,12 @@ func (rtr *Router) Execute(ctx context.Context, sql string, bindVars map[string]
}
// StreamExecute executes a streaming query.
func (rtr *Router) StreamExecute(ctx context.Context, sql string, bindVars map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
func (rtr *Router) StreamExecute(ctx context.Context, sql string, bindVars map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
if bindVars == nil {
bindVars = make(map[string]interface{})
}
vcursor := newRequestContext(ctx, sql, bindVars, tabletType, nil, false, rtr)
plan, err := rtr.planner.GetPlan(sql)
vcursor := newRequestContext(ctx, sql, bindVars, keyspace, tabletType, nil, false, rtr)
plan, err := rtr.planner.GetPlan(sql, keyspace)
if err != nil {
return err
}

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

@ -55,7 +55,7 @@ var routerVSchema = createTestVSchema(`
"Type": "numeric"
}
},
"Classes": {
"Tables": {
"user": {
"ColVindexes": [
{
@ -67,10 +67,10 @@ var routerVSchema = createTestVSchema(`
"Name": "name_user_map"
}
],
"Autoinc" : {
"Col": "id",
"Sequence": "user_seq"
}
"Autoinc" : {
"Col": "id",
"Sequence": "user_seq"
}
},
"user_extra": {
"ColVindexes": [
@ -91,10 +91,10 @@ var routerVSchema = createTestVSchema(`
"Name": "music_user_map"
}
],
"Autoinc" : {
"Col": "id",
"Sequence": "user_seq"
}
"Autoinc" : {
"Col": "id",
"Sequence": "user_seq"
}
},
"music_extra": {
"ColVindexes": [
@ -136,34 +136,22 @@ var routerVSchema = createTestVSchema(`
}
]
}
},
"Tables": {
"user": "user",
"user_extra": "user_extra",
"music": "music",
"music_extra": "music_extra",
"music_extra_reversed": "music_extra_reversed",
"noauto_table": "noauto_table",
"ksid_table": "ksid_table"
}
},
"TestBadSharding": {
"Sharded": false,
"Tables": {
"sharded_table": ""
"sharded_table": {}
}
},
"TestUnsharded": {
"Sharded": false,
"Classes": {
"seq": {
"Type": "Sequence"
}
},
"Tables": {
"user_seq": "seq",
"music_user_map": "",
"name_user_map": ""
"user_seq": {
"Type": "Sequence"
},
"music_user_map": {},
"name_user_map": {}
}
}
}
@ -215,6 +203,7 @@ func routerExec(router *Router, sql string, bv map[string]interface{}) (*sqltype
return router.Execute(context.Background(),
sql,
bv,
"",
topodatapb.TabletType_MASTER,
nil,
false)
@ -222,7 +211,7 @@ func routerExec(router *Router, sql string, bv map[string]interface{}) (*sqltype
func routerStream(router *Router, sql string) (qr *sqltypes.Result, err error) {
results := make(chan *sqltypes.Result, 10)
err = router.StreamExecute(context.Background(), sql, nil, topodatapb.TabletType_MASTER, func(qr *sqltypes.Result) error {
err = router.StreamExecute(context.Background(), sql, nil, "", topodatapb.TabletType_MASTER, func(qr *sqltypes.Result) error {
results <- qr
return nil
})

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

@ -562,6 +562,28 @@ func (sbc *sandboxConn) SplitQuery(ctx context.Context, query querytypes.BoundQu
return splits, nil
}
// Fake SplitQuery returns a single QuerySplit whose 'sql' field describes the received arguments.
// TODO(erez): Rename to SplitQuery after the migration to SplitQuery V2 is done.
func (sbc *sandboxConn) SplitQueryV2(
ctx context.Context,
query querytypes.BoundQuery,
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]querytypes.QuerySplit, error) {
// The sandbox stores the shard name in the endPoint Host field.
shard := sbc.endPoint.Host
splits := []querytypes.QuerySplit{
{
Sql: fmt.Sprintf(
"query:%v, splitColumns:%v, splitCount:%v,"+
" numRowsPerQueryPart:%v, algorithm:%v, shard:%v",
query, splitColumns, splitCount, numRowsPerQueryPart, algorithm, shard),
},
}
return splits, nil
}
// StreamHealth is not implemented.
func (sbc *sandboxConn) StreamHealth(ctx context.Context) (tabletconn.StreamHealthReader, error) {
return nil, fmt.Errorf("Not implemented in test")

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

@ -587,6 +587,85 @@ func (stc *ScatterConn) SplitQueryCustomSharding(ctx context.Context, sql string
return allSplits, nil
}
// SplitQueryV2 scatters a SplitQueryV2 request to the shards whose names are given in 'shards'.
// For every set of querytypes.QuerySplit's received from a shard, it applies the given
// 'querySplitToPartFunc' function to convert each querytypes.QuerySplit into a
// 'SplitQueryResponse_Part' message. Finally, it aggregates the obtained
// SplitQueryResponse_Parts across all shards and returns the resulting slice.
// TODO(erez): Remove 'scatterConn.SplitQuery' and rename this method to SplitQuery once
// the migration to SplitQuery V2 is done.
func (stc *ScatterConn) SplitQueryV2(
ctx context.Context,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
perShardSplitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
shards []string,
querySplitToQueryPartFunc func(
querySplit *querytypes.QuerySplit, shard string) (*vtgatepb.SplitQueryResponse_Part, error),
keyspace string) ([]*vtgatepb.SplitQueryResponse_Part, error) {
tabletType := topodatapb.TabletType_RDONLY
// allParts will collect the query-parts from all the shards. It's protected
// by allPartsMutex.
var allParts []*vtgatepb.SplitQueryResponse_Part
var allPartsMutex sync.Mutex
allErrors := stc.multiGo(
ctx,
"SplitQuery",
keyspace,
shards,
tabletType,
NewSafeSession(&vtgatepb.Session{}),
false,
func(shard string, transactionID int64) error {
// Get all splits from this shard
querySplits, err := stc.gateway.SplitQueryV2(
ctx,
keyspace,
shard,
tabletType,
sql,
bindVariables,
splitColumns,
perShardSplitCount,
numRowsPerQueryPart,
algorithm)
if err != nil {
return err
}
parts := make([]*vtgatepb.SplitQueryResponse_Part, len(querySplits))
for i, querySplit := range querySplits {
parts[i], err = querySplitToQueryPartFunc(&querySplit, shard)
if err != nil {
return err
}
}
// Aggregate the parts from this shard into allParts.
allPartsMutex.Lock()
defer allPartsMutex.Unlock()
allParts = append(allParts, parts...)
return nil
},
)
if allErrors.HasErrors() {
err := allErrors.AggrError(stc.aggregateErrors)
return nil, err
}
// We shuffle the query-parts here. External frameworks like MapReduce may
// "deal" these jobs to workers in the order they are in the list. Without
// shuffling workers can be very unevenly distributed among
// the shards they query. E.g. all workers will first query the first shard,
// then most of them to the second shard, etc, which results with uneven
// load balancing among shards.
shuffleQueryParts(allParts)
return allParts, nil
}
// randomGenerator is the randomGenerator used for the randomness
// of 'shuffleQueryParts'. It's initialized in 'init()' below.
type shuffleQueryPartsRandomGeneratorInterface interface {

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

@ -22,6 +22,7 @@ import (
"github.com/youtube/vitess/go/vt/vtgate/txbuffer"
"golang.org/x/net/context"
querypb "github.com/youtube/vitess/go/vt/proto/query"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
vtrpcpb "github.com/youtube/vitess/go/vt/proto/vtrpc"
)
@ -169,7 +170,9 @@ func (sdc *ShardConn) Begin(ctx context.Context) (transactionID int64, err error
err = sdc.withRetry(ctx, func(conn tabletconn.TabletConn) error {
var innerErr error
// Potentially buffer this transaction.
txbuffer.FakeBuffer(sdc.keyspace, sdc.shard, attemptNumber)
if bufferErr := txbuffer.FakeBuffer(sdc.keyspace, sdc.shard, attemptNumber); bufferErr != nil {
return bufferErr
}
transactionID, innerErr = conn.Begin(ctx)
attemptNumber++
return innerErr
@ -204,6 +207,28 @@ func (sdc *ShardConn) SplitQuery(ctx context.Context, sql string, bindVariables
return
}
// SplitQueryV2 splits a query into sub queries. The retry rules are the same as Execute.
// TODO(erez): Rename to SplitQuery after the migration to SplitQuery V2 is done.
func (sdc *ShardConn) SplitQueryV2(
ctx context.Context,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) (queries []querytypes.QuerySplit, err error) {
err = sdc.withRetry(ctx, func(conn tabletconn.TabletConn) error {
var innerErr error
queries, innerErr = conn.SplitQueryV2(ctx, querytypes.BoundQuery{
Sql: sql,
BindVariables: bindVariables,
}, splitColumns, splitCount, numRowsPerQueryPart, algorithm)
return innerErr
}, 0, false)
return
}
// Close closes the underlying TabletConn.
func (sdc *ShardConn) Close() {
if sdc.ticker != nil {

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

@ -19,6 +19,7 @@ import (
"github.com/youtube/vitess/go/vt/tabletserver/querytypes"
"github.com/youtube/vitess/go/vt/topo"
querypb "github.com/youtube/vitess/go/vt/proto/query"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)
@ -140,6 +141,23 @@ func (sg *shardGateway) SplitQuery(ctx context.Context, keyspace string, shard s
return sg.getConnection(ctx, keyspace, shard, tabletType).SplitQuery(ctx, sql, bindVars, splitColumn, splitCount)
}
// SplitQuery splits a query into sub-queries for the specified keyspace, shard, and tablet type.
// TODO(erez): Rename to SplitQuery after the migration to SplitQuery V2 is done.
func (sg *shardGateway) SplitQueryV2(
ctx context.Context,
keyspace string,
shard string,
tabletType topodatapb.TabletType,
sql string,
bindVars map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]querytypes.QuerySplit, error) {
return sg.getConnection(ctx, keyspace, shard, tabletType).SplitQueryV2(
ctx, sql, bindVars, splitColumns, splitCount, numRowsPerQueryPart, algorithm)
}
// Close shuts down the underlying connections.
func (sg *shardGateway) Close(ctx context.Context) error {
sg.mu.Lock()

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

@ -15,11 +15,14 @@ but will not return transient errors during the buffering time.
package txbuffer
import (
"errors"
"flag"
"sync"
"time"
"github.com/youtube/vitess/go/stats"
vtrpcpb "github.com/youtube/vitess/go/vt/proto/vtrpc"
"github.com/youtube/vitess/go/vt/vterrors"
)
var (
@ -39,26 +42,32 @@ var (
// timeSleep can be mocked out in unit tests
var timeSleep = time.Sleep
// errBufferFull is the error returned a buffer request is rejected because the buffer is full.
var errBufferFull = vterrors.FromError(
vtrpcpb.ErrorCode_TRANSIENT_ERROR,
errors.New("transaction buffer full, rejecting request"),
)
// FakeBuffer will pretend to buffer new transactions in VTGate.
// Transactions *will NOT actually be buffered*, they will just have a delayed start time.
// This can be useful to understand what the impact of trasaction buffering will be
// on upstream callers. Once the impact is measured, it can be used to tweak parameter values
// for the best behavior.
// FakeBuffer should be called before the VtTablet Begin, otherwise it will increase transaction times.
func FakeBuffer(keyspace, shard string, attemptNumber int) {
func FakeBuffer(keyspace, shard string, attemptNumber int) error {
// Only buffer on the first Begin attempt, not on possible retries.
if !*enableFakeTxBuffer || attemptNumber != 0 {
return
return nil
}
if keyspace != *bufferKeyspace || shard != *bufferShard {
return
return nil
}
bufferedTransactionsAttempted.Add(1)
bufferMu.Lock()
if int(bufferedTransactions.Get()) >= *maxBufferSize {
bufferMu.Unlock()
return
return errBufferFull
}
bufferedTransactions.Add(1)
bufferMu.Unlock()
@ -67,4 +76,5 @@ func FakeBuffer(keyspace, shard string, attemptNumber int) {
timeSleep(*fakeBufferDelay)
// Don't need to lock for this, as there's no race when decrementing the count
bufferedTransactions.Add(-1)
return nil
}

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

@ -58,6 +58,7 @@ func TestFakeBuffer(t *testing.T) {
wantCalled bool
// expected value of BufferedTransactionAttempts
wantAttempted int
wantErr error
}{
{
desc: "enableFakeBuffer=False",
@ -88,6 +89,7 @@ func TestFakeBuffer(t *testing.T) {
bufferedTransactions: *maxBufferSize,
// When the buffer is full, bufferedTransactionsAttempted should still be incremented
wantAttempted: 1,
wantErr: errBufferFull,
},
{
desc: "buffered successful",
@ -107,7 +109,11 @@ func TestFakeBuffer(t *testing.T) {
*enableFakeTxBuffer = test.enableFakeBuffer
FakeBuffer(test.keyspace, test.shard, test.attemptNumber)
gotErr := FakeBuffer(test.keyspace, test.shard, test.attemptNumber)
if gotErr != test.wantErr {
t.Errorf("With %v, FakeBuffer() => %v; want: %v", test.desc, gotErr, test.wantErr)
}
if controller.called != test.wantCalled {
t.Errorf("With %v, FakeBuffer() => timeSleep.called: %v; want: %v",
@ -162,23 +168,27 @@ func TestParallelFakeBuffer(t *testing.T) {
wg.Add(1)
finished := make(chan struct{})
var gotErr error
go func() {
defer wg.Done()
FakeBuffer(*bufferKeyspace, *bufferShard, 0)
gotErr = FakeBuffer(*bufferKeyspace, *bufferShard, 0)
close(finished)
}()
if wantFakeSleepCalled {
// the first maxBufferSize calls to FakeBuffer
// should call sleep, wait until they do
<-controller.blocked
} else {
// the rest should not block, wait until they're done
<-finished
// wait until either the gorouotine is blocked (because it's buffering) or until
// it's finished (because it shouldn't be buffered).
select {
case <-controller.blocked:
case <-finished:
}
if controller.called {
controllers = append(controllers, controller)
} else {
// if we didn't call fakeSleep, the buffer is full and should return an error saying so.
if gotErr != errBufferFull {
t.Errorf("On iteration %v, FakeBuffer() => %v; want: %v", i, gotErr, errBufferFull)
}
}
if controller.called != wantFakeSleepCalled {

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

@ -6,7 +6,6 @@ package vindexes
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"sort"
@ -16,7 +15,8 @@ import (
// VSchema represents the denormalized version of VSchemaFormal,
// used for building routing plans.
type VSchema struct {
Tables map[string]*Table
tables map[string]*Table
Keyspaces map[string]*KeyspaceSchema
}
// Table represnts a table in VSchema.
@ -45,6 +45,12 @@ type ColVindex struct {
Vindex Vindex
}
// KeyspaceSchema contains the schema(table) for a keyspace.
type KeyspaceSchema struct {
Keyspace *Keyspace
Tables map[string]*Table
}
// Autoinc contains the auto-inc information for a table.
type Autoinc struct {
Col string
@ -56,61 +62,62 @@ type Autoinc struct {
// BuildVSchema builds a VSchema from a VSchemaFormal.
func BuildVSchema(source *VSchemaFormal) (vschema *VSchema, err error) {
vschema = &VSchema{Tables: make(map[string]*Table)}
keyspaces := buildKeyspaces(source)
vschema = &VSchema{
tables: make(map[string]*Table),
Keyspaces: make(map[string]*KeyspaceSchema),
}
buildKeyspaces(source, vschema)
// We have to build the sequences first to avoid
// forward reference errors.
err = buildSequences(source, vschema, keyspaces)
err = buildSequences(source, vschema)
if err != nil {
return nil, err
}
err = buildTables(source, vschema, keyspaces)
err = buildTables(source, vschema)
if err != nil {
return nil, err
}
return vschema, nil
}
func buildKeyspaces(source *VSchemaFormal) map[string]*Keyspace {
k := make(map[string]*Keyspace)
func buildKeyspaces(source *VSchemaFormal, vschema *VSchema) {
for ksname, ks := range source.Keyspaces {
k[ksname] = &Keyspace{
Name: ksname,
Sharded: ks.Sharded,
vschema.Keyspaces[ksname] = &KeyspaceSchema{
Keyspace: &Keyspace{
Name: ksname,
Sharded: ks.Sharded,
},
Tables: make(map[string]*Table),
}
}
return k
}
func buildSequences(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*Keyspace) error {
func buildSequences(source *VSchemaFormal, vschema *VSchema) error {
for ksname, ks := range source.Keyspaces {
keyspace := keyspaces[ksname]
for tname, cname := range ks.Tables {
if _, ok := vschema.Tables[tname]; ok {
return fmt.Errorf("table %s has multiple definitions", tname)
}
if cname == "" {
keyspace := vschema.Keyspaces[ksname].Keyspace
for tname, table := range ks.Tables {
if table.Type != "Sequence" {
continue
}
class, ok := ks.Classes[cname]
if !ok {
return fmt.Errorf("class %s not found for table %s", cname, tname)
t := &Table{
Name: tname,
Keyspace: keyspace,
IsSequence: true,
}
if class.Type == "Sequence" {
vschema.Tables[tname] = &Table{
Name: tname,
Keyspace: keyspace,
IsSequence: true,
}
if _, ok := vschema.tables[tname]; ok {
vschema.tables[tname] = nil
} else {
vschema.tables[tname] = t
}
vschema.Keyspaces[ksname].Tables[tname] = t
}
}
return nil
}
func buildTables(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*Keyspace) error {
func buildTables(source *VSchemaFormal, vschema *VSchema) error {
for ksname, ks := range source.Keyspaces {
keyspace := keyspaces[ksname]
keyspace := vschema.Keyspaces[ksname].Keyspace
vindexes := make(map[string]Vindex)
for vname, vindexInfo := range ks.Vindexes {
vindex, err := CreateVindex(vindexInfo.Type, vname, vindexInfo.Params)
@ -125,29 +132,27 @@ func buildTables(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*
}
vindexes[vname] = vindex
}
for tname, cname := range ks.Tables {
if t, ok := vschema.Tables[tname]; ok {
if t.IsSequence {
continue
}
return fmt.Errorf("table %s has multiple definitions", tname)
for tname, table := range ks.Tables {
if table.Type == "Sequence" {
continue
}
t := &Table{
Name: tname,
Keyspace: keyspace,
}
if _, ok := vschema.tables[tname]; ok {
vschema.tables[tname] = nil
} else {
vschema.tables[tname] = t
}
vschema.Keyspaces[ksname].Tables[tname] = t
if !keyspace.Sharded {
vschema.Tables[tname] = t
continue
}
class, ok := ks.Classes[cname]
if !ok {
return fmt.Errorf("class %s not found for table %s", cname, tname)
}
for i, ind := range class.ColVindexes {
for i, ind := range table.ColVindexes {
vindexInfo, ok := ks.Vindexes[ind.Name]
if !ok {
return fmt.Errorf("vindex %s not found for class %s", ind.Name, cname)
return fmt.Errorf("vindex %s not found for table %s", ind.Name, tname)
}
vindex := vindexes[ind.Name]
owned := false
@ -164,10 +169,10 @@ func buildTables(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*
if i == 0 {
// Perform Primary vindex check.
if _, ok := columnVindex.Vindex.(Unique); !ok {
return fmt.Errorf("primary vindex %s is not Unique for class %s", ind.Name, cname)
return fmt.Errorf("primary vindex %s is not Unique for table %s", ind.Name, tname)
}
if owned {
return fmt.Errorf("primary vindex %s cannot be owned for class %s", ind.Name, cname)
return fmt.Errorf("primary vindex %s cannot be owned for table %s", ind.Name, tname)
}
}
t.ColVindexes = append(t.ColVindexes, columnVindex)
@ -176,11 +181,11 @@ func buildTables(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*
}
}
t.Ordered = colVindexSorted(t.ColVindexes)
if class.Autoinc != nil {
t.Autoinc = &Autoinc{Col: class.Autoinc.Col, ColVindexNum: -1}
seq, ok := vschema.Tables[class.Autoinc.Sequence]
if table.Autoinc != nil {
t.Autoinc = &Autoinc{Col: table.Autoinc.Col, ColVindexNum: -1}
seq, ok := vschema.tables[table.Autoinc.Sequence]
if !ok {
return fmt.Errorf("sequence %s not found for class %s", class.Autoinc.Sequence, cname)
return fmt.Errorf("sequence %s not found for table %s", table.Autoinc.Sequence, tname)
}
t.Autoinc.Sequence = seq
for i, cv := range t.ColVindexes {
@ -190,21 +195,48 @@ func buildTables(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*
}
}
}
vschema.Tables[tname] = t
}
}
return nil
}
// FindTable returns a pointer to the Table if found.
// Otherwise, it returns a reason, which is equivalent to an error.
func (vschema *VSchema) FindTable(tablename string) (table *Table, err error) {
if tablename == "" {
return nil, errors.New("unsupported: compex table expression in DML")
// Find returns a pointer to the Table. If a keyspace is specified, only tables
// from that keyspace are searched. If the specified keyspace is unsharded
// and no tables matched, it's considered valid: Find will construct a table
// of that name and return it. If no kesypace is specified, then a table is returned
// only if its name is unique across all keyspaces. If there is only one
// keyspace in the vschema, and it's unsharded, then all table requests are considered
// valid and belonging to that keyspace.
func (vschema *VSchema) Find(keyspace, tablename string) (table *Table, err error) {
if keyspace == "" {
table, ok := vschema.tables[tablename]
if table == nil {
if ok {
return nil, fmt.Errorf("ambiguous table reference: %s", tablename)
}
if len(vschema.Keyspaces) != 1 {
return nil, fmt.Errorf("table %s not found", tablename)
}
// Loop happens only once.
for _, ks := range vschema.Keyspaces {
if ks.Keyspace.Sharded {
return nil, fmt.Errorf("table %s not found", tablename)
}
return &Table{Name: tablename, Keyspace: ks.Keyspace}, nil
}
}
return table, nil
}
table = vschema.Tables[tablename]
ks, ok := vschema.Keyspaces[keyspace]
if !ok {
return nil, fmt.Errorf("keyspace %s not found in vschema", keyspace)
}
table = ks.Tables[tablename]
if table == nil {
return nil, fmt.Errorf("table %s not found", tablename)
if ks.Keyspace.Sharded {
return nil, fmt.Errorf("table %s not found", tablename)
}
return &Table{Name: tablename, Keyspace: ks.Keyspace}, nil
}
return table, nil
}
@ -236,8 +268,7 @@ type VSchemaFormal struct {
type KeyspaceFormal struct {
Sharded bool
Vindexes map[string]VindexFormal
Classes map[string]ClassFormal
Tables map[string]string
Tables map[string]TableFormal
}
// VindexFormal is the info for each index as loaded from
@ -248,9 +279,9 @@ type VindexFormal struct {
Owner string
}
// ClassFormal is the info for each table class as loaded from
// TableFormal is the info for each table as loaded from
// the source.
type ClassFormal struct {
type TableFormal struct {
Type string
ColVindexes []ColVindexFormal
Autoinc *AutoincFormal

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

@ -85,8 +85,8 @@ func TestUnshardedVSchema(t *testing.T) {
good := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"unsharded": {
Tables: map[string]string{
"t1": "",
Tables: map[string]TableFormal{
"t1": {},
},
},
},
@ -95,14 +95,23 @@ func TestUnshardedVSchema(t *testing.T) {
if err != nil {
t.Error(err)
}
ks := &Keyspace{
Name: "unsharded",
}
t1 := &Table{
Name: "t1",
Keyspace: ks,
}
want := &VSchema{
Tables: map[string]*Table{
"t1": {
Name: "t1",
Keyspace: &Keyspace{
Name: "unsharded",
tables: map[string]*Table{
"t1": t1,
},
Keyspaces: map[string]*KeyspaceSchema{
"unsharded": {
Keyspace: ks,
Tables: map[string]*Table{
"t1": t1,
},
ColVindexes: nil,
},
},
}
@ -129,7 +138,7 @@ func TestShardedVSchemaOwned(t *testing.T) {
Owner: "t1",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
@ -142,9 +151,6 @@ func TestShardedVSchemaOwned(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
@ -152,42 +158,52 @@ func TestShardedVSchemaOwned(t *testing.T) {
if err != nil {
t.Error(err)
}
want := &VSchema{
Tables: map[string]*Table{
"t1": {
Name: "t1",
Keyspace: &Keyspace{
Name: "sharded",
Sharded: true,
ks := &Keyspace{
Name: "sharded",
Sharded: true,
}
t1 := &Table{
Name: "t1",
Keyspace: ks,
ColVindexes: []*ColVindex{
{
Col: "c1",
Type: "stfu",
Name: "stfu1",
Vindex: &stFU{
name: "stfu1",
Params: map[string]interface{}{
"stfu1": 1,
},
},
ColVindexes: []*ColVindex{
{
Col: "c1",
Type: "stfu",
Name: "stfu1",
Vindex: &stFU{
name: "stfu1",
Params: map[string]interface{}{
"stfu1": 1,
},
},
},
{
Col: "c2",
Type: "stln",
Name: "stln1",
Owned: true,
Vindex: &stLN{name: "stln1"},
},
},
{
Col: "c2",
Type: "stln",
Name: "stln1",
Owned: true,
Vindex: &stLN{name: "stln1"},
},
},
}
t1.Ordered = []*ColVindex{
t1.ColVindexes[1],
t1.ColVindexes[0],
}
t1.Owned = t1.ColVindexes[1:]
want := &VSchema{
tables: map[string]*Table{
"t1": t1,
},
Keyspaces: map[string]*KeyspaceSchema{
"sharded": {
Keyspace: ks,
Tables: map[string]*Table{
"t1": t1,
},
},
},
}
want.Tables["t1"].Ordered = []*ColVindex{
want.Tables["t1"].ColVindexes[1],
want.Tables["t1"].ColVindexes[0],
}
want.Tables["t1"].Owned = want.Tables["t1"].ColVindexes[1:]
if !reflect.DeepEqual(got, want) {
gotjson, _ := json.Marshal(got)
wantjson, _ := json.Marshal(want)
@ -210,7 +226,7 @@ func TestShardedVSchemaNotOwned(t *testing.T) {
Owner: "",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
@ -223,9 +239,6 @@ func TestShardedVSchemaNotOwned(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
@ -233,36 +246,46 @@ func TestShardedVSchemaNotOwned(t *testing.T) {
if err != nil {
t.Error(err)
}
want := &VSchema{
Tables: map[string]*Table{
"t1": {
Name: "t1",
Keyspace: &Keyspace{
Name: "sharded",
Sharded: true,
},
ColVindexes: []*ColVindex{
{
Col: "c1",
Type: "stlu",
Name: "stlu1",
Owned: false,
Vindex: &stLU{name: "stlu1"},
},
{
Col: "c2",
Type: "stfu",
Name: "stfu1",
Owned: false,
Vindex: &stFU{name: "stfu1"},
},
},
ks := &Keyspace{
Name: "sharded",
Sharded: true,
}
t1 := &Table{
Name: "t1",
Keyspace: ks,
ColVindexes: []*ColVindex{
{
Col: "c1",
Type: "stlu",
Name: "stlu1",
Owned: false,
Vindex: &stLU{name: "stlu1"},
},
{
Col: "c2",
Type: "stfu",
Name: "stfu1",
Owned: false,
Vindex: &stFU{name: "stfu1"},
},
},
}
want.Tables["t1"].Ordered = []*ColVindex{
want.Tables["t1"].ColVindexes[1],
want.Tables["t1"].ColVindexes[0],
t1.Ordered = []*ColVindex{
t1.ColVindexes[1],
t1.ColVindexes[0],
}
want := &VSchema{
tables: map[string]*Table{
"t1": t1,
},
Keyspaces: map[string]*KeyspaceSchema{
"sharded": {
Keyspace: ks,
Tables: map[string]*Table{
"t1": t1,
},
},
},
}
if !reflect.DeepEqual(got, want) {
t.Errorf("BuildVSchema:s\n%v, want\n%v", got, want)
@ -283,39 +306,6 @@ func TestLoadVSchemaFail(t *testing.T) {
}
}
func TestBuildVSchemaClassNotFoundFail(t *testing.T) {
bad := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"sharded": {
Sharded: true,
Vindexes: map[string]VindexFormal{
"stfu": {
Type: "stfu",
},
},
Classes: map[string]ClassFormal{
"notexist": {
ColVindexes: []ColVindexFormal{
{
Col: "c1",
Name: "noexist",
},
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
_, err := BuildVSchema(&bad)
want := "class t1 not found for table t1"
if err == nil || err.Error() != want {
t.Errorf("BuildVSchema: %v, want %v", err, want)
}
}
func TestBuildVSchemaVindexNotFoundFail(t *testing.T) {
bad := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
@ -326,7 +316,7 @@ func TestBuildVSchemaVindexNotFoundFail(t *testing.T) {
Type: "noexist",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
@ -336,9 +326,6 @@ func TestBuildVSchemaVindexNotFoundFail(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
@ -359,7 +346,7 @@ func TestBuildVSchemaInvalidVindexFail(t *testing.T) {
Type: "stf",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
@ -369,9 +356,6 @@ func TestBuildVSchemaInvalidVindexFail(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
@ -382,57 +366,121 @@ func TestBuildVSchemaInvalidVindexFail(t *testing.T) {
}
}
func TestBuildVSchemaDupTableFail(t *testing.T) {
bad := VSchemaFormal{
func TestBuildVSchemaDupSeq(t *testing.T) {
good := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"sharded": {
Sharded: true,
Vindexes: map[string]VindexFormal{
"stfu": {
Type: "stfu",
},
},
Classes: map[string]ClassFormal{
"ksa": {
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
Col: "c1",
Name: "stfu",
},
},
Type: "Sequence",
},
},
Tables: map[string]string{
"t1": "t1",
},
},
"sharded1": {
Sharded: true,
Vindexes: map[string]VindexFormal{
"stfu": {
Type: "stfu",
},
},
Classes: map[string]ClassFormal{
"ksb": {
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
Col: "c1",
Name: "stfu",
},
},
Type: "Sequence",
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
_, err := BuildVSchema(&bad)
want := "table t1 has multiple definitions"
if err == nil || err.Error() != want {
t.Errorf("BuildVSchema: %v, want %v", err, want)
ksa := &Keyspace{
Name: "ksa",
}
ksb := &Keyspace{
Name: "ksb",
}
got, _ := BuildVSchema(&good)
t1a := &Table{
Name: "t1",
Keyspace: ksa,
IsSequence: true,
}
t1b := &Table{
Name: "t1",
Keyspace: ksb,
IsSequence: true,
}
want := &VSchema{
tables: map[string]*Table{
"t1": nil,
},
Keyspaces: map[string]*KeyspaceSchema{
"ksa": {
Keyspace: ksa,
Tables: map[string]*Table{
"t1": t1a,
},
},
"ksb": {
Keyspace: ksb,
Tables: map[string]*Table{
"t1": t1b,
},
},
},
}
if !reflect.DeepEqual(got, want) {
gotjson, _ := json.Marshal(got)
wantjson, _ := json.Marshal(want)
t.Errorf("BuildVSchema:s\n%s, want\n%s", gotjson, wantjson)
}
}
func TestBuildVSchemaDupTable(t *testing.T) {
good := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"ksa": {
Tables: map[string]TableFormal{
"t1": {},
},
},
"ksb": {
Tables: map[string]TableFormal{
"t1": {},
},
},
},
}
got, _ := BuildVSchema(&good)
ksa := &Keyspace{
Name: "ksa",
}
t1a := &Table{
Name: "t1",
Keyspace: ksa,
}
ksb := &Keyspace{
Name: "ksb",
}
t1b := &Table{
Name: "t1",
Keyspace: ksb,
}
want := &VSchema{
tables: map[string]*Table{
"t1": nil,
},
Keyspaces: map[string]*KeyspaceSchema{
"ksa": {
Keyspace: ksa,
Tables: map[string]*Table{
"t1": t1a,
},
},
"ksb": {
Keyspace: ksb,
Tables: map[string]*Table{
"t1": t1b,
},
},
},
}
if !reflect.DeepEqual(got, want) {
gotjson, _ := json.Marshal(got)
wantjson, _ := json.Marshal(want)
t.Errorf("BuildVSchema:s\n%s, want\n%s", gotjson, wantjson)
}
}
@ -446,7 +494,7 @@ func TestBuildVSchemaNoindexFail(t *testing.T) {
Type: "stfu",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
@ -456,14 +504,11 @@ func TestBuildVSchemaNoindexFail(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
_, err := BuildVSchema(&bad)
want := "vindex notexist not found for class t1"
want := "vindex notexist not found for table t1"
if err == nil || err.Error() != want {
t.Errorf("BuildVSchema: %v, want %v", err, want)
}
@ -479,7 +524,7 @@ func TestBuildVSchemaNotUniqueFail(t *testing.T) {
Type: "stln",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
@ -489,14 +534,11 @@ func TestBuildVSchemaNotUniqueFail(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
_, err := BuildVSchema(&bad)
want := "primary vindex stln is not Unique for class t1"
want := "primary vindex stln is not Unique for table t1"
if err == nil || err.Error() != want {
t.Errorf("BuildVSchema: %v, want %v", err, want)
}
@ -513,7 +555,7 @@ func TestBuildVSchemaPrimaryNonFunctionalFail(t *testing.T) {
Owner: "t1",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
@ -523,14 +565,11 @@ func TestBuildVSchemaPrimaryNonFunctionalFail(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
_, err := BuildVSchema(&bad)
want := "primary vindex stlu cannot be owned for class t1"
want := "primary vindex stlu cannot be owned for table t1"
if err == nil || err.Error() != want {
t.Errorf("BuildVSchema: %v, want %v", err, want)
}
@ -540,14 +579,11 @@ func TestSequence(t *testing.T) {
good := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"unsharded": {
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"seq": {
Type: "Sequence",
},
},
Tables: map[string]string{
"seq": "seq",
},
},
"sharded": {
Sharded: true,
@ -559,7 +595,7 @@ func TestSequence(t *testing.T) {
},
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
@ -573,9 +609,6 @@ func TestSequence(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
@ -583,44 +616,61 @@ func TestSequence(t *testing.T) {
if err != nil {
t.Error(err)
}
ksu := &Keyspace{
Name: "unsharded",
}
kss := &Keyspace{
Name: "sharded",
Sharded: true,
}
seq := &Table{
Name: "seq",
Keyspace: &Keyspace{
Name: "unsharded",
},
Name: "seq",
Keyspace: ksu,
IsSequence: true,
}
want := &VSchema{
Tables: map[string]*Table{
"seq": seq,
"t1": {
Name: "t1",
Keyspace: &Keyspace{
Name: "sharded",
Sharded: true,
},
ColVindexes: []*ColVindex{
{
Col: "c1",
Type: "stfu",
Name: "stfu1",
Vindex: &stFU{
name: "stfu1",
Params: map[string]interface{}{
"stfu1": 1,
},
},
t1 := &Table{
Name: "t1",
Keyspace: kss,
ColVindexes: []*ColVindex{
{
Col: "c1",
Type: "stfu",
Name: "stfu1",
Vindex: &stFU{
name: "stfu1",
Params: map[string]interface{}{
"stfu1": 1,
},
},
Autoinc: &Autoinc{
Col: "c1",
Sequence: seq,
},
},
},
Autoinc: &Autoinc{
Col: "c1",
Sequence: seq,
},
}
want.Tables["t1"].Ordered = []*ColVindex{
want.Tables["t1"].ColVindexes[0],
t1.Ordered = []*ColVindex{
t1.ColVindexes[0],
}
want := &VSchema{
tables: map[string]*Table{
"seq": seq,
"t1": t1,
},
Keyspaces: map[string]*KeyspaceSchema{
"unsharded": {
Keyspace: ksu,
Tables: map[string]*Table{
"seq": seq,
},
},
"sharded": {
Keyspace: kss,
Tables: map[string]*Table{
"t1": t1,
},
},
},
}
if !reflect.DeepEqual(got, want) {
gotjson, _ := json.Marshal(got)
@ -630,11 +680,11 @@ func TestSequence(t *testing.T) {
}
func TestBadSequence(t *testing.T) {
good := VSchemaFormal{
bad := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"sharded": {
Sharded: true,
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
Autoinc: &AutoincFormal{
Col: "c1",
@ -642,15 +692,122 @@ func TestBadSequence(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
_, err := BuildVSchema(&good)
want := "sequence seq not found for class t1"
_, err := BuildVSchema(&bad)
want := "sequence seq not found for table t1"
if err == nil || err.Error() != want {
t.Errorf("BuildVSchema: %v, want %v", err, want)
}
}
func TestFind(t *testing.T) {
input := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"ksa": {
Tables: map[string]TableFormal{
"ta": {},
"t1": {},
},
},
"ksb": {
Sharded: true,
Tables: map[string]TableFormal{
"tb": {},
"t1": {},
},
},
},
}
vschema, _ := BuildVSchema(&input)
_, err := vschema.Find("", "t1")
wantErr := "ambiguous table reference: t1"
if err == nil || err.Error() != wantErr {
t.Errorf("Find(\"\"): %v, want %s", err, wantErr)
}
_, err = vschema.Find("", "none")
wantErr = "table none not found"
if err == nil || err.Error() != wantErr {
t.Errorf("Find(\"\"): %v, want %s", err, wantErr)
}
got, err := vschema.Find("", "ta")
if err != nil {
t.Error(err)
return
}
ta := &Table{
Name: "ta",
Keyspace: &Keyspace{
Name: "ksa",
},
}
if !reflect.DeepEqual(got, ta) {
t.Errorf("Find(\"t1a\"): %+v, want %+v", got, ta)
}
got, err = vschema.Find("ksa", "ta")
if !reflect.DeepEqual(got, ta) {
t.Errorf("Find(\"t1a\"): %+v, want %+v", got, ta)
}
none := &Table{
Name: "none",
Keyspace: &Keyspace{
Name: "ksa",
},
}
got, err = vschema.Find("ksa", "none")
if !reflect.DeepEqual(got, none) {
t.Errorf("Find(\"t1a\"): %+v, want %+v", got, none)
}
_, err = vschema.Find("ksb", "none")
wantErr = "table none not found"
if err == nil || err.Error() != wantErr {
t.Errorf("Find(\"\"): %v, want %s", err, wantErr)
}
_, err = vschema.Find("none", "aa")
wantErr = "keyspace none not found in vschema"
if err == nil || err.Error() != wantErr {
t.Errorf("Find(\"\"): %v, want %s", err, wantErr)
}
}
func TestFindSingleKeyspace(t *testing.T) {
input := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"ksa": {
Tables: map[string]TableFormal{
"ta": {},
"t1": {},
},
},
},
}
vschema, _ := BuildVSchema(&input)
none := &Table{
Name: "none",
Keyspace: &Keyspace{
Name: "ksa",
},
}
got, _ := vschema.Find("", "none")
if !reflect.DeepEqual(got, none) {
t.Errorf("Find(\"t1a\"): %+v, want %+v", got, none)
}
input = VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"ksb": {
Sharded: true,
Tables: map[string]TableFormal{
"tb": {},
"t1": {},
},
},
},
}
vschema, _ = BuildVSchema(&input)
_, err := vschema.Find("", "none")
wantErr := "table none not found"
if err == nil || err.Error() != wantErr {
t.Errorf("Find(\"\"): %v, want %s", err, wantErr)
}
}

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

@ -24,6 +24,7 @@ import (
"github.com/youtube/vitess/go/vt/logutil"
"github.com/youtube/vitess/go/vt/servenv"
"github.com/youtube/vitess/go/vt/sqlannotation"
"github.com/youtube/vitess/go/vt/tabletserver/querytypes"
"github.com/youtube/vitess/go/vt/tabletserver/tabletconn"
"github.com/youtube/vitess/go/vt/topo"
"github.com/youtube/vitess/go/vt/vterrors"
@ -31,6 +32,7 @@ import (
"github.com/youtube/vitess/go/vt/vtgate/vindexes"
"github.com/youtube/vitess/go/vt/vtgate/vtgateservice"
querypb "github.com/youtube/vitess/go/vt/proto/query"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
vtgatepb "github.com/youtube/vitess/go/vt/proto/vtgate"
vtrpcpb "github.com/youtube/vitess/go/vt/proto/vtrpc"
@ -155,7 +157,7 @@ func (vtg *VTGate) InitializeConnections(ctx context.Context) (err error) {
}
// Execute executes a non-streaming query by routing based on the values in the query.
func (vtg *VTGate) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
func (vtg *VTGate) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
startTime := time.Now()
statsKey := []string{"Execute", "Any", strings.ToLower(tabletType.String())}
defer vtg.timings.Record(statsKey, startTime)
@ -166,7 +168,7 @@ func (vtg *VTGate) Execute(ctx context.Context, sql string, bindVariables map[st
return nil, errTooManyInFlight
}
qr, err := vtg.router.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction)
qr, err := vtg.router.Execute(ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
if err == nil {
vtg.rowsReturned.Add(statsKey, int64(len(qr.Rows)))
return qr, nil
@ -175,6 +177,7 @@ func (vtg *VTGate) Execute(ctx context.Context, sql string, bindVariables map[st
query := map[string]interface{}{
"Sql": sql,
"BindVariables": bindVariables,
"Keyspace": keyspace,
"TabletType": strings.ToLower(tabletType.String()),
"Session": session,
"NotInTransaction": notInTransaction,
@ -408,7 +411,7 @@ func (vtg *VTGate) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vtgat
}
// StreamExecute executes a streaming query by routing based on the values in the query.
func (vtg *VTGate) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
func (vtg *VTGate) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
startTime := time.Now()
statsKey := []string{"StreamExecute", "Any", strings.ToLower(tabletType.String())}
defer vtg.timings.Record(statsKey, startTime)
@ -424,6 +427,7 @@ func (vtg *VTGate) StreamExecute(ctx context.Context, sql string, bindVariables
ctx,
sql,
bindVariables,
keyspace,
tabletType,
func(reply *sqltypes.Result) error {
rowCount += int64(len(reply.Rows))
@ -436,6 +440,7 @@ func (vtg *VTGate) StreamExecute(ctx context.Context, sql string, bindVariables
query := map[string]interface{}{
"Sql": sql,
"BindVariables": bindVariables,
"Keyspace": keyspace,
"TabletType": strings.ToLower(tabletType.String()),
}
logError(err, query, vtg.logStreamExecute)
@ -627,6 +632,132 @@ func (vtg *VTGate) SplitQuery(ctx context.Context, keyspace string, sql string,
return vtg.resolver.scatterConn.SplitQueryCustomSharding(ctx, sql, bindVariables, splitColumn, perShardSplitCount, shardNames, keyspace)
}
// SplitQueryV2 implements the SplitQuery RPC. This is the new version that
// supports multiple split-columns and multiple splitting algorithms.
// See the documentation of SplitQueryRequest in "proto/vtgate.proto" for more
// information.
// TODO(erez): Remove 'SplitQuery' and rename this method to 'SplitQuery' once the migration
// to SplitQuery-V2 is done.
func (vtg *VTGate) SplitQueryV2(
ctx context.Context,
keyspace string,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]*vtgatepb.SplitQueryResponse_Part, error) {
// TODO(erez): Add validation of SplitQuery parameters.
keyspace, srvKeyspace, shardRefs, err := getKeyspaceShards(
ctx, vtg.resolver.toposerv, vtg.resolver.cell, keyspace, topodatapb.TabletType_RDONLY)
if err != nil {
return nil, err
}
// If the caller specified a splitCount (vs. specifying 'numRowsPerQueryPart') scale it by the
// number of shards (otherwise it stays 0).
perShardSplitCount := int64(math.Ceil(float64(splitCount) / float64(len(shardRefs))))
// Determine whether to return SplitQueryResponse_KeyRangeParts or SplitQueryResponse_ShardParts.
// We return 'KeyRangeParts' for sharded keyspaces that are not custom sharded. If the
// keyspace is custom sharded or unsharded we return 'ShardParts'.
var querySplitToQueryPartFunc func(
querySplit *querytypes.QuerySplit, shard string) (*vtgatepb.SplitQueryResponse_Part, error)
// sharding_column_type != KeyspaceIdType_UNSET can happen in one of the following two cases:
// 1. We are querying a sharded keyspace;
// 2. We are querying an unsharded keyspace which is being sharded.
if srvKeyspace.ShardingColumnType != topodatapb.KeyspaceIdType_UNSET {
// Index the shard references in 'shardRefs' by shard name.
shardRefByName := make(map[string]*topodatapb.ShardReference, len(shardRefs))
for _, shardRef := range shardRefs {
shardRefByName[shardRef.Name] = shardRef
}
querySplitToQueryPartFunc = getQuerySplitToKeyRangePartFunc(keyspace, shardRefByName)
} else {
// Keyspace is either unsharded or custom-sharded.
querySplitToQueryPartFunc = getQuerySplitToShardPartFunc(keyspace)
}
// Collect all shard names into a slice.
shardNames := make([]string, 0, len(shardRefs))
for _, shardRef := range shardRefs {
shardNames = append(shardNames, shardRef.Name)
}
return vtg.resolver.scatterConn.SplitQueryV2(
ctx,
sql,
bindVariables,
splitColumns,
perShardSplitCount,
numRowsPerQueryPart,
algorithm,
shardNames,
querySplitToQueryPartFunc,
keyspace)
}
// getQuerySplitToKeyRangePartFunc returns a function to use with scatterConn.SplitQueryV2
// that converts the given QuerySplit to a SplitQueryResponse_Part message whose KeyRangePart field
// is set.
func getQuerySplitToKeyRangePartFunc(
keyspace string,
shardReferenceByName map[string]*topodatapb.ShardReference) func(
querySplit *querytypes.QuerySplit, shard string) (*vtgatepb.SplitQueryResponse_Part, error) {
return func(
querySplit *querytypes.QuerySplit, shard string) (*vtgatepb.SplitQueryResponse_Part, error) {
// TODO(erez): Assert that shardReferenceByName contains an entry for 'shard'.
// Keyrange can be nil for the shard (e.g. for single-sharded keyspaces during resharding).
// In this case we append an empty keyrange that represents the entire keyspace.
keyranges := []*topodatapb.KeyRange{{Start: []byte{}, End: []byte{}}}
if shardReferenceByName[shard].KeyRange != nil {
keyranges = []*topodatapb.KeyRange{shardReferenceByName[shard].KeyRange}
}
bindVars, err := querytypes.BindVariablesToProto3(querySplit.BindVariables)
if err != nil {
return nil, err
}
return &vtgatepb.SplitQueryResponse_Part{
Query: &querypb.BoundQuery{
Sql: querySplit.Sql,
BindVariables: bindVars,
},
KeyRangePart: &vtgatepb.SplitQueryResponse_KeyRangePart{
Keyspace: keyspace,
KeyRanges: keyranges,
},
Size: querySplit.RowCount,
}, nil
}
}
// getQuerySplitToShardPartFunc returns a function to use with scatterConn.SplitQueryV2
// that converts the given QuerySplit to a SplitQueryResponse_Part message whose ShardPart field
// is set.
func getQuerySplitToShardPartFunc(keyspace string) func(
querySplit *querytypes.QuerySplit, shard string) (*vtgatepb.SplitQueryResponse_Part, error) {
return func(
querySplit *querytypes.QuerySplit, shard string) (*vtgatepb.SplitQueryResponse_Part, error) {
bindVars, err := querytypes.BindVariablesToProto3(querySplit.BindVariables)
if err != nil {
return nil, err
}
return &vtgatepb.SplitQueryResponse_Part{
Query: &querypb.BoundQuery{
Sql: querySplit.Sql,
BindVariables: bindVars,
},
ShardPart: &vtgatepb.SplitQueryResponse_ShardPart{
Keyspace: keyspace,
Shards: []string{shard},
},
Size: querySplit.RowCount,
}, nil
}
}
// GetSrvKeyspace is part of the vtgate service API.
func (vtg *VTGate) GetSrvKeyspace(ctx context.Context, keyspace string) (*topodatapb.SrvKeyspace, error) {
return vtg.resolver.toposerv.GetSrvKeyspace(ctx, vtg.resolver.cell, keyspace)

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

@ -7,6 +7,7 @@ package vtgate
import (
"encoding/hex"
"fmt"
"math"
"reflect"
"sort"
"strings"
@ -34,7 +35,7 @@ func init() {
"TestUnsharded": {
"Sharded": false,
"Tables": {
"t1": ""
"t1": {}
}
}
}
@ -50,6 +51,7 @@ func TestVTGateExecute(t *testing.T) {
qr, err := rpcVTGate.Execute(context.Background(),
"select id from t1",
nil,
"",
topodatapb.TabletType_MASTER,
nil,
false)
@ -67,6 +69,7 @@ func TestVTGateExecute(t *testing.T) {
rpcVTGate.Execute(context.Background(),
"select id from t1",
nil,
"",
topodatapb.TabletType_MASTER,
session,
false)
@ -94,12 +97,43 @@ func TestVTGateExecute(t *testing.T) {
rpcVTGate.Execute(context.Background(),
"select id from t1",
nil,
"",
topodatapb.TabletType_MASTER,
session,
false)
rpcVTGate.Rollback(context.Background(), session)
}
func TestVTGateExecuteWithKeyspace(t *testing.T) {
sandbox := createSandbox(KsTestUnsharded)
sbc := &sandboxConn{}
sandbox.MapTestConn("0", sbc)
qr, err := rpcVTGate.Execute(context.Background(),
"select id from none",
nil,
KsTestUnsharded,
topodatapb.TabletType_MASTER,
nil,
false)
if err != nil {
t.Errorf("want nil, got %v", err)
}
if !reflect.DeepEqual(singleRowResult, qr) {
t.Errorf("want \n%+v, got \n%+v", singleRowResult, qr)
}
_, err = rpcVTGate.Execute(context.Background(),
"select id from none",
nil,
"aa",
topodatapb.TabletType_MASTER,
nil,
false)
want := "keyspace aa not found in vschema"
if err == nil || err.Error() != want {
t.Errorf("Execute: %v, want %s", err, want)
}
}
func TestVTGateExecuteShards(t *testing.T) {
sandbox := createSandbox("TestVTGateExecuteShards")
sbc := &sandboxConn{}
@ -531,6 +565,7 @@ func TestVTGateStreamExecute(t *testing.T) {
err := rpcVTGate.StreamExecute(context.Background(),
"select id from t1",
nil,
"",
topodatapb.TabletType_MASTER,
func(r *sqltypes.Result) error {
qrs = append(qrs, r)
@ -728,6 +763,159 @@ func TestVTGateSplitQuery(t *testing.T) {
}
}
// TODO(erez): Rename after migration to SplitQuery V2 is done.
func TestVTGateSplitQueryV2Sharded(t *testing.T) {
keyspace := "TestVTGateSplitQuery"
keyranges, err := key.ParseShardingSpec(DefaultShardSpec)
if err != nil {
t.Fatalf("got: %v, want: nil", err)
}
s := createSandbox(keyspace)
for _, kr := range keyranges {
s.MapTestConn(key.KeyRangeString(kr), &sandboxConn{})
}
sql := "select col1, col2 from table"
bindVars := map[string]interface{}{"bv1": nil}
splitColumns := []string{"sc1", "sc2"}
algorithm := querypb.SplitQueryRequest_FULL_SCAN
type testCaseType struct {
splitCount int64
numRowsPerQueryPart int64
algorithm querypb.SplitQueryRequest_Algorithm
}
testCases := []testCaseType{
{splitCount: 100, numRowsPerQueryPart: 0},
{splitCount: 0, numRowsPerQueryPart: 123},
}
for _, testCase := range testCases {
splits, err := rpcVTGate.SplitQueryV2(
context.Background(),
keyspace,
sql,
bindVars,
splitColumns,
testCase.splitCount,
testCase.numRowsPerQueryPart,
algorithm)
if err != nil {
t.Errorf("got %v, want: nil. testCase: %+v", err, testCase)
}
// Total number of splits should be number of shards as our sandbox returns a single split
// for its fake implementation of SplitQuery.
if len(keyranges) != len(splits) {
t.Errorf("wrong number of splits, got %+v, want %+v. testCase:\n%+v",
len(splits), len(keyranges), testCase)
}
actualSqlsByKeyRange := map[string][]string{}
for _, split := range splits {
if split.KeyRangePart.Keyspace != keyspace {
t.Errorf("wrong keyspace, got \n%+v, want \n%+v. testCase:\n%+v",
keyspace, split.KeyRangePart.Keyspace, testCase)
}
if len(split.KeyRangePart.KeyRanges) != 1 {
t.Errorf("wrong number of keyranges, got \n%+v, want \n%+v. testCase:\n%+v",
1, len(split.KeyRangePart.KeyRanges), testCase)
}
kr := key.KeyRangeString(split.KeyRangePart.KeyRanges[0])
actualSqlsByKeyRange[kr] = append(actualSqlsByKeyRange[kr], split.Query.Sql)
}
expectedSqlsByKeyRange := map[string][]string{}
for _, kr := range keyranges {
perShardSplitCount := int64(math.Ceil(float64(testCase.splitCount) / float64(len(keyranges))))
shard := key.KeyRangeString(kr)
expectedSqlsByKeyRange[shard] = []string{
fmt.Sprintf(
"query:%v, splitColumns:%v, splitCount:%v,"+
" numRowsPerQueryPart:%v, algorithm:%v, shard:%v",
querytypes.BoundQuery{Sql: sql, BindVariables: bindVars},
splitColumns,
perShardSplitCount,
testCase.numRowsPerQueryPart,
algorithm,
shard,
),
}
}
if !reflect.DeepEqual(actualSqlsByKeyRange, expectedSqlsByKeyRange) {
t.Errorf(
"splits contain the wrong sqls and/or keyranges, "+
"got:\n%+v\n, want:\n%+v\n. testCase:\n%+v",
actualSqlsByKeyRange, expectedSqlsByKeyRange, testCase)
}
}
}
func TestVTGateSplitQueryV2Unsharded(t *testing.T) {
keyspace := KsTestUnsharded
s := getSandbox(keyspace)
if s == nil {
t.Fatalf("Can't find unsharded sandbox.")
}
s.MapTestConn("0", &sandboxConn{})
sql := "select col1, col2 from table"
bindVars := map[string]interface{}{"bv1": nil}
splitColumns := []string{"sc1", "sc2"}
algorithm := querypb.SplitQueryRequest_FULL_SCAN
type testCaseType struct {
splitCount int64
numRowsPerQueryPart int64
algorithm querypb.SplitQueryRequest_Algorithm
}
testCases := []testCaseType{
{splitCount: 100, numRowsPerQueryPart: 0},
{splitCount: 0, numRowsPerQueryPart: 123},
}
for _, testCase := range testCases {
splits, err := rpcVTGate.SplitQueryV2(
context.Background(),
keyspace,
sql,
bindVars,
splitColumns,
testCase.splitCount,
testCase.numRowsPerQueryPart,
algorithm)
if err != nil {
t.Errorf("got %v, want: nil. testCase: %+v", err, testCase)
}
// Total number of splits should be number of shards (1) as our sandbox returns a single split
// for its fake implementation of SplitQuery.
if 1 != len(splits) {
t.Errorf("wrong number of splits, got %+v, want %+v. testCase:\n%+v",
len(splits), 1, testCase)
continue
}
split := splits[0]
if split.KeyRangePart != nil {
t.Errorf("KeyRangePart should not be populated. Got:\n%+v\n, testCase:\n%+v\n",
keyspace, split.KeyRangePart)
}
if split.ShardPart.Keyspace != keyspace {
t.Errorf("wrong keyspace, got \n%+v, want \n%+v. testCase:\n%+v",
keyspace, split.ShardPart.Keyspace, testCase)
}
if len(split.ShardPart.Shards) != 1 {
t.Errorf("wrong number of shards, got \n%+v, want \n%+v. testCase:\n%+v",
1, len(split.ShardPart.Shards), testCase)
}
expectedShard := "0"
expectedSQL := fmt.Sprintf(
"query:%v, splitColumns:%v, splitCount:%v,"+
" numRowsPerQueryPart:%v, algorithm:%v, shard:%v",
querytypes.BoundQuery{Sql: sql, BindVariables: bindVars},
splitColumns,
testCase.splitCount,
testCase.numRowsPerQueryPart,
algorithm,
expectedShard,
)
if split.Query.Sql != expectedSQL {
t.Errorf("got:\n%v\n, want:\n%v\n, testCase:\n%+v",
split.Query.Sql, expectedSQL, testCase)
}
}
}
func TestIsErrorCausedByVTGate(t *testing.T) {
unknownError := fmt.Errorf("unknown error")
serverError := &tabletconn.ServerError{

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

@ -13,6 +13,7 @@ import (
"github.com/youtube/vitess/go/sqltypes"
"golang.org/x/net/context"
querypb "github.com/youtube/vitess/go/vt/proto/query"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
vtgatepb "github.com/youtube/vitess/go/vt/proto/vtgate"
)
@ -150,6 +151,25 @@ func (conn *VTGateConn) SplitQuery(ctx context.Context, keyspace string, query s
return conn.impl.SplitQuery(ctx, keyspace, query, bindVars, splitColumn, splitCount)
}
// SplitQueryV2 splits a query into smaller queries. It is mostly used by batch job frameworks
// such as MapReduce. See the documentation for the vtgate.SplitQueryRequest protocol buffer message
// in 'proto/vtgate.proto'.
// TODO(erez): Rename to SplitQuery after the migration to SplitQuery V2 is done.
func (conn *VTGateConn) SplitQueryV2(
ctx context.Context,
keyspace string,
query string,
bindVars map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm,
) ([]*vtgatepb.SplitQueryResponse_Part, error) {
return conn.impl.SplitQueryV2(
ctx, keyspace, query, bindVars, splitColumns, splitCount, numRowsPerQueryPart, algorithm)
}
// GetSrvKeyspace returns a topo.SrvKeyspace object.
func (conn *VTGateConn) GetSrvKeyspace(ctx context.Context, keyspace string) (*topodatapb.SrvKeyspace, error) {
return conn.impl.GetSrvKeyspace(ctx, keyspace)
@ -334,6 +354,20 @@ type Impl interface {
// appending primary key range clauses to the original query.
SplitQuery(ctx context.Context, keyspace string, query string, bindVars map[string]interface{}, splitColumn string, splitCount int64) ([]*vtgatepb.SplitQueryResponse_Part, error)
// SplitQuery splits a query into smaller queries. It is mostly used by batch job frameworks
// such as MapReduce. See the documentation for the vtgate.SplitQueryRequest protocol buffer
// message in 'proto/vtgate.proto'.
// TODO(erez): Rename to SplitQuery after the migration to SplitQuery V2 is done.
SplitQueryV2(
ctx context.Context,
keyspace string,
query string,
bindVars map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]*vtgatepb.SplitQueryResponse_Part, error)
// GetSrvKeyspace returns a topo.SrvKeyspace.
GetSrvKeyspace(ctx context.Context, keyspace string) (*topodatapb.SrvKeyspace, error)

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

@ -74,13 +74,14 @@ func (f *fakeVTGateService) checkCallerID(ctx context.Context, name string) {
type queryExecute struct {
SQL string
BindVariables map[string]interface{}
Keyspace string
TabletType topodatapb.TabletType
Session *vtgatepb.Session
NotInTransaction bool
}
// Execute is part of the VTGateService interface
func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if f.hasError {
return nil, errTestVtGateError
}
@ -95,6 +96,7 @@ func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariabl
query := &queryExecute{
SQL: sql,
BindVariables: bindVariables,
Keyspace: keyspace,
TabletType: tabletType,
Session: session,
NotInTransaction: notInTransaction,
@ -370,7 +372,7 @@ func (f *fakeVTGateService) ExecuteBatchKeyspaceIds(ctx context.Context, queries
}
// StreamExecute is part of the VTGateService interface
func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
if f.panics {
panic(fmt.Errorf("test forced panic"))
}
@ -382,6 +384,7 @@ func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindV
query := &queryExecute{
SQL: sql,
BindVariables: bindVariables,
Keyspace: keyspace,
TabletType: tabletType,
}
if !reflect.DeepEqual(query, execCase.execQuery) {
@ -630,6 +633,51 @@ func (f *fakeVTGateService) SplitQuery(ctx context.Context, keyspace string, sql
return splitQueryResult, nil
}
// querySplitQueryV2 contains all the fields we use to test SplitQuery
// TODO(erez): Rename to querySplitQuery after the migration to SplitQuery is done.
type querySplitQueryV2 struct {
Keyspace string
SQL string
BindVariables map[string]interface{}
SplitColumns []string
SplitCount int64
NumRowsPerQueryPart int64
Algorithm querypb.SplitQueryRequest_Algorithm
}
// SplitQueryV2 is part of the VTGateService interface
// TODO(erez): Rename to SplitQuery after the migration to SplitQuery is done.
func (f *fakeVTGateService) SplitQueryV2(
ctx context.Context,
keyspace string,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]*vtgatepb.SplitQueryResponse_Part, error) {
if f.hasError {
return nil, errTestVtGateError
}
if f.panics {
panic(fmt.Errorf("test forced panic"))
}
f.checkCallerID(ctx, "SplitQuery")
query := &querySplitQueryV2{
Keyspace: keyspace,
SQL: sql,
BindVariables: bindVariables,
SplitColumns: splitColumns,
SplitCount: splitCount,
NumRowsPerQueryPart: numRowsPerQueryPart,
Algorithm: algorithm,
}
if !reflect.DeepEqual(query, splitQueryV2Request) {
f.t.Errorf("SplitQuery has wrong input: got %#v wanted %#v", query, splitQueryRequest)
}
return splitQueryResult, nil
}
// GetSrvKeyspace is part of the VTGateService interface
func (f *fakeVTGateService) GetSrvKeyspace(ctx context.Context, keyspace string) (*topodatapb.SrvKeyspace, error) {
if f.hasError {
@ -705,6 +753,7 @@ func TestSuite(t *testing.T, impl vtgateconn.Impl, fakeServer vtgateservice.VTGa
testTx2Pass(t, conn)
testTx2Fail(t, conn)
testSplitQuery(t, conn)
testSplitQueryV2(t, conn)
testGetSrvKeyspace(t, conn)
// force a panic at every call, then test that works
@ -732,6 +781,7 @@ func TestSuite(t *testing.T, impl vtgateconn.Impl, fakeServer vtgateservice.VTGa
testStreamExecuteKeyRangesPanic(t, conn)
testStreamExecuteKeyspaceIdsPanic(t, conn)
testSplitQueryPanic(t, conn)
testSplitQueryV2Panic(t, conn)
testGetSrvKeyspacePanic(t, conn)
fs.panics = false
}
@ -770,6 +820,7 @@ func TestErrorSuite(t *testing.T, fakeServer vtgateservice.VTGateService) {
testStreamExecuteKeyRangesError(t, conn, fs)
testStreamExecuteKeyspaceIdsError(t, conn, fs)
testSplitQueryError(t, conn)
testSplitQueryV2Error(t, conn)
testGetSrvKeyspaceError(t, conn)
fs.hasError = false
}
@ -1879,15 +1930,72 @@ func testSplitQuery(t *testing.T, conn *vtgateconn.VTGateConn) {
}
}
// TODO(erez): Rename to testSplitQuery after migration to SplitQuery V2 is done.
func testSplitQueryV2(t *testing.T, conn *vtgateconn.VTGateConn) {
ctx := newContext()
qsl, err := conn.SplitQueryV2(ctx,
splitQueryV2Request.Keyspace,
splitQueryV2Request.SQL,
splitQueryV2Request.BindVariables,
splitQueryV2Request.SplitColumns,
splitQueryV2Request.SplitCount,
splitQueryV2Request.NumRowsPerQueryPart,
splitQueryV2Request.Algorithm,
)
if err != nil {
t.Fatalf("SplitQuery failed: %v", err)
}
if len(qsl) == 1 && len(qsl[0].Query.BindVariables) == 1 {
bv := qsl[0].Query.BindVariables["bind1"]
if len(bv.Values) == 0 {
bv.Values = nil
}
}
if !reflect.DeepEqual(qsl, splitQueryResult) {
t.Errorf("SplitQuery returned wrong result: got %#v wanted %#v", qsl, splitQueryResult)
}
}
func testSplitQueryError(t *testing.T, conn *vtgateconn.VTGateConn) {
ctx := newContext()
_, err := conn.SplitQuery(ctx, splitQueryRequest.Keyspace, splitQueryRequest.SQL, splitQueryRequest.BindVariables, splitQueryRequest.SplitColumn, splitQueryRequest.SplitCount)
verifyError(t, err, "SplitQuery")
}
// TODO(erez): Rename to testSplitQueryError after migration to SplitQuery V2 is done.
func testSplitQueryV2Error(t *testing.T, conn *vtgateconn.VTGateConn) {
ctx := newContext()
_, err := conn.SplitQueryV2(ctx,
splitQueryV2Request.Keyspace,
splitQueryV2Request.SQL,
splitQueryV2Request.BindVariables,
splitQueryV2Request.SplitColumns,
splitQueryV2Request.SplitCount,
splitQueryV2Request.NumRowsPerQueryPart,
splitQueryV2Request.Algorithm,
)
verifyError(t, err, "SplitQuery")
}
func testSplitQueryPanic(t *testing.T, conn *vtgateconn.VTGateConn) {
ctx := newContext()
_, err := conn.SplitQuery(ctx, splitQueryRequest.Keyspace, splitQueryRequest.SQL, splitQueryRequest.BindVariables, splitQueryRequest.SplitColumn, splitQueryRequest.SplitCount)
expectPanic(t, err)
}
// TODO(erez): Rename to testSplitQueryPanic after migration to SplitQuery V2 is done.
func testSplitQueryV2Panic(t *testing.T, conn *vtgateconn.VTGateConn) {
ctx := newContext()
_, err := conn.SplitQueryV2(ctx,
splitQueryV2Request.Keyspace,
splitQueryV2Request.SQL,
splitQueryV2Request.BindVariables,
splitQueryV2Request.SplitColumns,
splitQueryV2Request.SplitCount,
splitQueryV2Request.NumRowsPerQueryPart,
splitQueryV2Request.Algorithm,
)
expectPanic(t, err)
}
@ -2315,6 +2423,18 @@ var splitQueryRequest = &querySplitQuery{
SplitCount: 13,
}
var splitQueryV2Request = &querySplitQueryV2{
Keyspace: "ks2",
SQL: "in for SplitQueryV2",
BindVariables: map[string]interface{}{
"bind2": int64(43),
},
SplitColumns: []string{"split_column1", "split_column2"},
SplitCount: 145,
NumRowsPerQueryPart: 4000,
Algorithm: querypb.SplitQueryRequest_FULL_SCAN,
}
var splitQueryResult = []*vtgatepb.SplitQueryResponse_Part{
{
Query: &querypb.BoundQuery{

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

@ -10,6 +10,7 @@ import (
"github.com/youtube/vitess/go/sqltypes"
"golang.org/x/net/context"
querypb "github.com/youtube/vitess/go/vt/proto/query"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
vtgatepb "github.com/youtube/vitess/go/vt/proto/vtgate"
)
@ -19,7 +20,7 @@ import (
type VTGateService interface {
// Regular query execution.
// All these methods can change the provided session.
Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error)
Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error)
ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error)
ExecuteKeyspaceIds(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyspaceIds [][]byte, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error)
ExecuteKeyRanges(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyRanges []*topodatapb.KeyRange, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error)
@ -28,7 +29,7 @@ type VTGateService interface {
ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vtgatepb.BoundKeyspaceIdQuery, tabletType topodatapb.TabletType, asTransaction bool, session *vtgatepb.Session) ([]sqltypes.Result, error)
// Streaming queries
StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error
StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error
StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error
StreamExecuteKeyspaceIds(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyspaceIds [][]byte, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error
StreamExecuteKeyRanges(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyRanges []*topodatapb.KeyRange, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error
@ -41,6 +42,18 @@ type VTGateService interface {
// Map Reduce support
SplitQuery(ctx context.Context, keyspace string, sql string, bindVariables map[string]interface{}, splitColumn string, splitCount int64) ([]*vtgatepb.SplitQueryResponse_Part, error)
// MapReduce support
// TODO(erez): Rename to SplitQuery after migration to SplitQuery V2.
SplitQueryV2(
ctx context.Context,
keyspace string,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]*vtgatepb.SplitQueryResponse_Part, error)
// Topology support
GetSrvKeyspace(ctx context.Context, keyspace string) (*topodatapb.SrvKeyspace, error)
@ -52,3 +65,56 @@ type VTGateService interface {
// RPC implementation method, before calling any of the previous methods
HandlePanic(err *error)
}
// CallCorrectSplitQuery calls the correct SplitQuery.
// This trivial logic is encapsulated in a function here so it can be easily tested.
// TODO(erez): Remove once the migration to SplitQueryV2 is done.
func CallCorrectSplitQuery(
vtgateService VTGateService,
useSplitQueryV2 bool,
ctx context.Context,
keyspace string,
sql string,
bindVariables map[string]interface{},
splitColumns []string,
splitCount int64,
numRowsPerQueryPart int64,
algorithm querypb.SplitQueryRequest_Algorithm) ([]*vtgatepb.SplitQueryResponse_Part, error) {
if useSplitQueryV2 {
return vtgateService.SplitQueryV2(
ctx,
keyspace,
sql,
bindVariables,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm)
}
return vtgateService.SplitQuery(
ctx,
keyspace,
sql,
bindVariables,
splitColumnsToSplitColumn(splitColumns),
splitCount)
}
// SplitColumnsToSplitColumn returns the first SplitColumn in the given slice or an empty
// string if the slice is empty.
//
// This method is used to get the traditional behavior when accessing the SplitColumn field in an
// older SplitQuery-V1 vtgatepb.SplitQueryRequest represented in the newer SplitQuery-V2
// vtgatepb.SplitQueryRequest message. In the new V2 message the SplitColumn field has been
// converted into a repeated string field.
// TODO(erez): Remove this function when migration to SplitQueryV2 is done.
func splitColumnsToSplitColumn(splitColumns []string) string {
if len(splitColumns) == 0 {
return ""
}
return splitColumns[0]
}
// Command to generate a mock for this interface with mockgen.
//go:generate mockgen -source $GOFILE -destination vtgateservice_testing/mock_vtgateservice.go -package vtgateservice_testing

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

@ -0,0 +1,122 @@
package vtgateservice
import (
"testing"
"github.com/golang/mock/gomock"
"golang.org/x/net/context"
querypb "github.com/youtube/vitess/go/vt/proto/query"
"github.com/youtube/vitess/go/vt/vtgate/vtgateservice/vtgateservice_testing"
)
var (
keyspace = "It's a keyspace!"
sql = "It's an SQL statement!"
bindVariables = map[string]interface{}{}
splitCount int64 = 123
numRowsPerQueryPart int64 = 456
algorithm = querypb.SplitQueryRequest_EQUAL_SPLITS
)
func TestCallCorrectSplitQueryCallV1NoSplitColumn(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockVTGateService := vtgateservice_testing.NewMockVTGateService(mockCtrl)
mockVTGateService.EXPECT().SplitQuery(
context.Background(),
keyspace,
sql,
bindVariables,
"",
splitCount)
CallCorrectSplitQuery(
mockVTGateService,
false, /* useSplitQueryV2 */
context.Background(),
keyspace,
sql,
bindVariables,
[]string{}, /* SplitColumns */
splitCount,
numRowsPerQueryPart,
algorithm)
}
func TestCallCorrectSplitQueryCallV1SplitColumnEmpty(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockVTGateService := vtgateservice_testing.NewMockVTGateService(mockCtrl)
mockVTGateService.EXPECT().SplitQuery(
context.Background(),
keyspace,
sql,
bindVariables,
"",
splitCount)
CallCorrectSplitQuery(
mockVTGateService,
false, /* useSplitQueryV2 */
context.Background(),
keyspace,
sql,
bindVariables,
[]string{""}, /* SplitColumns */
splitCount,
numRowsPerQueryPart,
algorithm)
}
func TestCallCorrectSplitQueryCallV1WithSplitColumn(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockVTGateService := vtgateservice_testing.NewMockVTGateService(mockCtrl)
mockVTGateService.EXPECT().SplitQuery(
context.Background(),
keyspace,
sql,
bindVariables,
"First Split Column",
splitCount)
CallCorrectSplitQuery(
mockVTGateService,
false, /* useSplitQueryV2 */
context.Background(),
keyspace,
sql,
bindVariables,
[]string{"First Split Column"}, /* SplitColumns */
splitCount,
numRowsPerQueryPart,
algorithm)
}
func TestCallCorrectSplitQueryCallV2(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockVTGateService := vtgateservice_testing.NewMockVTGateService(mockCtrl)
splitColumns := []string{"col1", "col2"}
mockVTGateService.EXPECT().SplitQueryV2(
context.Background(),
keyspace,
sql,
bindVariables,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm)
CallCorrectSplitQuery(
mockVTGateService,
true, /* useSplitQueryV2 */
context.Background(),
keyspace,
sql,
bindVariables,
splitColumns,
splitCount,
numRowsPerQueryPart,
algorithm)
}

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

@ -0,0 +1,234 @@
// Automatically generated by MockGen. DO NOT EDIT!
// Source: interface.go
package vtgateservice_testing
import (
gomock "github.com/golang/mock/gomock"
sqltypes "github.com/youtube/vitess/go/sqltypes"
query "github.com/youtube/vitess/go/vt/proto/query"
topodata "github.com/youtube/vitess/go/vt/proto/topodata"
vtgate "github.com/youtube/vitess/go/vt/proto/vtgate"
context "golang.org/x/net/context"
)
// Mock of VTGateService interface
type MockVTGateService struct {
ctrl *gomock.Controller
recorder *_MockVTGateServiceRecorder
}
// Recorder for MockVTGateService (not exported)
type _MockVTGateServiceRecorder struct {
mock *MockVTGateService
}
func NewMockVTGateService(ctrl *gomock.Controller) *MockVTGateService {
mock := &MockVTGateService{ctrl: ctrl}
mock.recorder = &_MockVTGateServiceRecorder{mock}
return mock
}
func (_m *MockVTGateService) EXPECT() *_MockVTGateServiceRecorder {
return _m.recorder
}
func (_m *MockVTGateService) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodata.TabletType, session *vtgate.Session, notInTransaction bool) (*sqltypes.Result, error) {
ret := _m.ctrl.Call(_m, "Execute", ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
ret0, _ := ret[0].(*sqltypes.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) Execute(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Execute", arg0, arg1, arg2, arg3, arg4, arg5, arg6)
}
func (_m *MockVTGateService) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodata.TabletType, session *vtgate.Session, notInTransaction bool) (*sqltypes.Result, error) {
ret := _m.ctrl.Call(_m, "ExecuteShards", ctx, sql, bindVariables, keyspace, shards, tabletType, session, notInTransaction)
ret0, _ := ret[0].(*sqltypes.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) ExecuteShards(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "ExecuteShards", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
}
func (_m *MockVTGateService) ExecuteKeyspaceIds(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyspaceIds [][]byte, tabletType topodata.TabletType, session *vtgate.Session, notInTransaction bool) (*sqltypes.Result, error) {
ret := _m.ctrl.Call(_m, "ExecuteKeyspaceIds", ctx, sql, bindVariables, keyspace, keyspaceIds, tabletType, session, notInTransaction)
ret0, _ := ret[0].(*sqltypes.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) ExecuteKeyspaceIds(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "ExecuteKeyspaceIds", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
}
func (_m *MockVTGateService) ExecuteKeyRanges(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyRanges []*topodata.KeyRange, tabletType topodata.TabletType, session *vtgate.Session, notInTransaction bool) (*sqltypes.Result, error) {
ret := _m.ctrl.Call(_m, "ExecuteKeyRanges", ctx, sql, bindVariables, keyspace, keyRanges, tabletType, session, notInTransaction)
ret0, _ := ret[0].(*sqltypes.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) ExecuteKeyRanges(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "ExecuteKeyRanges", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
}
func (_m *MockVTGateService) ExecuteEntityIds(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, entityColumnName string, entityKeyspaceIDs []*vtgate.ExecuteEntityIdsRequest_EntityId, tabletType topodata.TabletType, session *vtgate.Session, notInTransaction bool) (*sqltypes.Result, error) {
ret := _m.ctrl.Call(_m, "ExecuteEntityIds", ctx, sql, bindVariables, keyspace, entityColumnName, entityKeyspaceIDs, tabletType, session, notInTransaction)
ret0, _ := ret[0].(*sqltypes.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) ExecuteEntityIds(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "ExecuteEntityIds", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
}
func (_m *MockVTGateService) ExecuteBatchShards(ctx context.Context, queries []*vtgate.BoundShardQuery, tabletType topodata.TabletType, asTransaction bool, session *vtgate.Session) ([]sqltypes.Result, error) {
ret := _m.ctrl.Call(_m, "ExecuteBatchShards", ctx, queries, tabletType, asTransaction, session)
ret0, _ := ret[0].([]sqltypes.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) ExecuteBatchShards(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "ExecuteBatchShards", arg0, arg1, arg2, arg3, arg4)
}
func (_m *MockVTGateService) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vtgate.BoundKeyspaceIdQuery, tabletType topodata.TabletType, asTransaction bool, session *vtgate.Session) ([]sqltypes.Result, error) {
ret := _m.ctrl.Call(_m, "ExecuteBatchKeyspaceIds", ctx, queries, tabletType, asTransaction, session)
ret0, _ := ret[0].([]sqltypes.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) ExecuteBatchKeyspaceIds(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "ExecuteBatchKeyspaceIds", arg0, arg1, arg2, arg3, arg4)
}
func (_m *MockVTGateService) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodata.TabletType, sendReply func(*sqltypes.Result) error) error {
ret := _m.ctrl.Call(_m, "StreamExecute", ctx, sql, bindVariables, keyspace, tabletType, sendReply)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockVTGateServiceRecorder) StreamExecute(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "StreamExecute", arg0, arg1, arg2, arg3, arg4, arg5)
}
func (_m *MockVTGateService) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodata.TabletType, sendReply func(*sqltypes.Result) error) error {
ret := _m.ctrl.Call(_m, "StreamExecuteShards", ctx, sql, bindVariables, keyspace, shards, tabletType, sendReply)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockVTGateServiceRecorder) StreamExecuteShards(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "StreamExecuteShards", arg0, arg1, arg2, arg3, arg4, arg5, arg6)
}
func (_m *MockVTGateService) StreamExecuteKeyspaceIds(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyspaceIds [][]byte, tabletType topodata.TabletType, sendReply func(*sqltypes.Result) error) error {
ret := _m.ctrl.Call(_m, "StreamExecuteKeyspaceIds", ctx, sql, bindVariables, keyspace, keyspaceIds, tabletType, sendReply)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockVTGateServiceRecorder) StreamExecuteKeyspaceIds(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "StreamExecuteKeyspaceIds", arg0, arg1, arg2, arg3, arg4, arg5, arg6)
}
func (_m *MockVTGateService) StreamExecuteKeyRanges(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyRanges []*topodata.KeyRange, tabletType topodata.TabletType, sendReply func(*sqltypes.Result) error) error {
ret := _m.ctrl.Call(_m, "StreamExecuteKeyRanges", ctx, sql, bindVariables, keyspace, keyRanges, tabletType, sendReply)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockVTGateServiceRecorder) StreamExecuteKeyRanges(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "StreamExecuteKeyRanges", arg0, arg1, arg2, arg3, arg4, arg5, arg6)
}
func (_m *MockVTGateService) Begin(ctx context.Context) (*vtgate.Session, error) {
ret := _m.ctrl.Call(_m, "Begin", ctx)
ret0, _ := ret[0].(*vtgate.Session)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) Begin(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Begin", arg0)
}
func (_m *MockVTGateService) Commit(ctx context.Context, session *vtgate.Session) error {
ret := _m.ctrl.Call(_m, "Commit", ctx, session)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockVTGateServiceRecorder) Commit(arg0, arg1 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Commit", arg0, arg1)
}
func (_m *MockVTGateService) Rollback(ctx context.Context, session *vtgate.Session) error {
ret := _m.ctrl.Call(_m, "Rollback", ctx, session)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockVTGateServiceRecorder) Rollback(arg0, arg1 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Rollback", arg0, arg1)
}
func (_m *MockVTGateService) SplitQuery(ctx context.Context, keyspace string, sql string, bindVariables map[string]interface{}, splitColumn string, splitCount int64) ([]*vtgate.SplitQueryResponse_Part, error) {
ret := _m.ctrl.Call(_m, "SplitQuery", ctx, keyspace, sql, bindVariables, splitColumn, splitCount)
ret0, _ := ret[0].([]*vtgate.SplitQueryResponse_Part)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) SplitQuery(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "SplitQuery", arg0, arg1, arg2, arg3, arg4, arg5)
}
func (_m *MockVTGateService) SplitQueryV2(ctx context.Context, keyspace string, sql string, bindVariables map[string]interface{}, splitColumns []string, splitCount int64, numRowsPerQueryPart int64, algorithm query.SplitQueryRequest_Algorithm) ([]*vtgate.SplitQueryResponse_Part, error) {
ret := _m.ctrl.Call(_m, "SplitQueryV2", ctx, keyspace, sql, bindVariables, splitColumns, splitCount, numRowsPerQueryPart, algorithm)
ret0, _ := ret[0].([]*vtgate.SplitQueryResponse_Part)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) SplitQueryV2(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "SplitQueryV2", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
}
func (_m *MockVTGateService) GetSrvKeyspace(ctx context.Context, keyspace string) (*topodata.SrvKeyspace, error) {
ret := _m.ctrl.Call(_m, "GetSrvKeyspace", ctx, keyspace)
ret0, _ := ret[0].(*topodata.SrvKeyspace)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) GetSrvKeyspace(arg0, arg1 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "GetSrvKeyspace", arg0, arg1)
}
func (_m *MockVTGateService) GetSrvShard(ctx context.Context, keyspace string, shard string) (*topodata.SrvShard, error) {
ret := _m.ctrl.Call(_m, "GetSrvShard", ctx, keyspace, shard)
ret0, _ := ret[0].(*topodata.SrvShard)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) GetSrvShard(arg0, arg1, arg2 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "GetSrvShard", arg0, arg1, arg2)
}
func (_m *MockVTGateService) HandlePanic(err *error) {
_m.ctrl.Call(_m, "HandlePanic", err)
}
func (_mr *_MockVTGateServiceRecorder) HandlePanic(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "HandlePanic", arg0)
}

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

@ -371,6 +371,7 @@ public final class VTGateConn implements Closeable {
}));
}
// TODO(erez): Migrate to SplitQueryV2 after it's stable.
public SQLFuture<List<SplitQueryResponse.Part>> splitQuery(
Context ctx,
String keyspace,
@ -383,8 +384,9 @@ public final class VTGateConn implements Closeable {
SplitQueryRequest.newBuilder()
.setKeyspace(checkNotNull(keyspace))
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
.setSplitColumn(checkNotNull(splitColumn))
.setSplitCount(splitCount);
.addSplitColumn(checkNotNull(splitColumn))
.setSplitCount(splitCount)
.setUseSplitQueryV2(false);
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}

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

@ -18,15 +18,24 @@ namespace Vitess\Proto\Query {
/** @var \Vitess\Proto\Query\BoundQuery */
public $query = null;
/** @var string */
public $split_column = null;
/** @var string[] */
public $split_column = array();
/** @var int */
public $split_count = null;
/** @var int */
public $num_rows_per_query_part = null;
/** @var int */
public $session_id = null;
/** @var int - \Vitess\Proto\Query\SplitQueryRequest\Algorithm */
public $algorithm = null;
/** @var boolean */
public $use_split_query_v2 = null;
/** @var \Closure[] */
protected static $__extensions = array();
@ -71,12 +80,12 @@ namespace Vitess\Proto\Query {
$f->reference = '\Vitess\Proto\Query\BoundQuery';
$descriptor->addField($f);
// OPTIONAL STRING split_column = 5
// REPEATED STRING split_column = 5
$f = new \DrSlump\Protobuf\Field();
$f->number = 5;
$f->name = "split_column";
$f->type = \DrSlump\Protobuf::TYPE_STRING;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$f->rule = \DrSlump\Protobuf::RULE_REPEATED;
$descriptor->addField($f);
// OPTIONAL INT64 split_count = 6
@ -87,6 +96,14 @@ namespace Vitess\Proto\Query {
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
// OPTIONAL INT64 num_rows_per_query_part = 8
$f = new \DrSlump\Protobuf\Field();
$f->number = 8;
$f->name = "num_rows_per_query_part";
$f->type = \DrSlump\Protobuf::TYPE_INT64;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
// OPTIONAL INT64 session_id = 7
$f = new \DrSlump\Protobuf\Field();
$f->number = 7;
@ -95,6 +112,23 @@ namespace Vitess\Proto\Query {
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
// OPTIONAL ENUM algorithm = 9
$f = new \DrSlump\Protobuf\Field();
$f->number = 9;
$f->name = "algorithm";
$f->type = \DrSlump\Protobuf::TYPE_ENUM;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$f->reference = '\Vitess\Proto\Query\SplitQueryRequest\Algorithm';
$descriptor->addField($f);
// OPTIONAL BOOL use_split_query_v2 = 10
$f = new \DrSlump\Protobuf\Field();
$f->number = 10;
$f->name = "use_split_query_v2";
$f->type = \DrSlump\Protobuf::TYPE_BOOL;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
foreach (self::$__extensions as $cb) {
$descriptor->addField($cb(), true);
}
@ -271,10 +305,11 @@ namespace Vitess\Proto\Query {
/**
* Get <split_column> value
*
* @param int $idx
* @return string
*/
public function getSplitColumn(){
return $this->_get(5);
public function getSplitColumn($idx = NULL){
return $this->_get(5, $idx);
}
/**
@ -283,8 +318,27 @@ namespace Vitess\Proto\Query {
* @param string $value
* @return \Vitess\Proto\Query\SplitQueryRequest
*/
public function setSplitColumn( $value){
return $this->_set(5, $value);
public function setSplitColumn( $value, $idx = NULL){
return $this->_set(5, $value, $idx);
}
/**
* Get all elements of <split_column>
*
* @return string[]
*/
public function getSplitColumnList(){
return $this->_get(5);
}
/**
* Add a new element to <split_column>
*
* @param string $value
* @return \Vitess\Proto\Query\SplitQueryRequest
*/
public function addSplitColumn( $value){
return $this->_add(5, $value);
}
/**
@ -324,6 +378,43 @@ namespace Vitess\Proto\Query {
return $this->_set(6, $value);
}
/**
* Check if <num_rows_per_query_part> has a value
*
* @return boolean
*/
public function hasNumRowsPerQueryPart(){
return $this->_has(8);
}
/**
* Clear <num_rows_per_query_part> value
*
* @return \Vitess\Proto\Query\SplitQueryRequest
*/
public function clearNumRowsPerQueryPart(){
return $this->_clear(8);
}
/**
* Get <num_rows_per_query_part> value
*
* @return int
*/
public function getNumRowsPerQueryPart(){
return $this->_get(8);
}
/**
* Set <num_rows_per_query_part> value
*
* @param int $value
* @return \Vitess\Proto\Query\SplitQueryRequest
*/
public function setNumRowsPerQueryPart( $value){
return $this->_set(8, $value);
}
/**
* Check if <session_id> has a value
*
@ -360,6 +451,80 @@ namespace Vitess\Proto\Query {
public function setSessionId( $value){
return $this->_set(7, $value);
}
/**
* Check if <algorithm> has a value
*
* @return boolean
*/
public function hasAlgorithm(){
return $this->_has(9);
}
/**
* Clear <algorithm> value
*
* @return \Vitess\Proto\Query\SplitQueryRequest
*/
public function clearAlgorithm(){
return $this->_clear(9);
}
/**
* Get <algorithm> value
*
* @return int - \Vitess\Proto\Query\SplitQueryRequest\Algorithm
*/
public function getAlgorithm(){
return $this->_get(9);
}
/**
* Set <algorithm> value
*
* @param int - \Vitess\Proto\Query\SplitQueryRequest\Algorithm $value
* @return \Vitess\Proto\Query\SplitQueryRequest
*/
public function setAlgorithm( $value){
return $this->_set(9, $value);
}
/**
* Check if <use_split_query_v2> has a value
*
* @return boolean
*/
public function hasUseSplitQueryV2(){
return $this->_has(10);
}
/**
* Clear <use_split_query_v2> value
*
* @return \Vitess\Proto\Query\SplitQueryRequest
*/
public function clearUseSplitQueryV2(){
return $this->_clear(10);
}
/**
* Get <use_split_query_v2> value
*
* @return boolean
*/
public function getUseSplitQueryV2(){
return $this->_get(10);
}
/**
* Set <use_split_query_v2> value
*
* @param boolean $value
* @return \Vitess\Proto\Query\SplitQueryRequest
*/
public function setUseSplitQueryV2( $value){
return $this->_set(10, $value);
}
}
}

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

@ -0,0 +1,11 @@
<?php
// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
// Source: query.proto
namespace Vitess\Proto\Query\SplitQueryRequest {
class Algorithm extends \DrSlump\Protobuf\Enum {
const EQUAL_SPLITS = 0;
const FULL_SCAN = 1;
}
}

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

@ -15,12 +15,21 @@ namespace Vitess\Proto\Vtgate {
/** @var \Vitess\Proto\Query\BoundQuery */
public $query = null;
/** @var string */
public $split_column = null;
/** @var string[] */
public $split_column = array();
/** @var int */
public $split_count = null;
/** @var int */
public $num_rows_per_query_part = null;
/** @var int - \Vitess\Proto\Query\SplitQueryRequest\Algorithm */
public $algorithm = null;
/** @var boolean */
public $use_split_query_v2 = null;
/** @var \Closure[] */
protected static $__extensions = array();
@ -55,12 +64,12 @@ namespace Vitess\Proto\Vtgate {
$f->reference = '\Vitess\Proto\Query\BoundQuery';
$descriptor->addField($f);
// OPTIONAL STRING split_column = 4
// REPEATED STRING split_column = 4
$f = new \DrSlump\Protobuf\Field();
$f->number = 4;
$f->name = "split_column";
$f->type = \DrSlump\Protobuf::TYPE_STRING;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$f->rule = \DrSlump\Protobuf::RULE_REPEATED;
$descriptor->addField($f);
// OPTIONAL INT64 split_count = 5
@ -71,6 +80,31 @@ namespace Vitess\Proto\Vtgate {
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
// OPTIONAL INT64 num_rows_per_query_part = 6
$f = new \DrSlump\Protobuf\Field();
$f->number = 6;
$f->name = "num_rows_per_query_part";
$f->type = \DrSlump\Protobuf::TYPE_INT64;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
// OPTIONAL ENUM algorithm = 7
$f = new \DrSlump\Protobuf\Field();
$f->number = 7;
$f->name = "algorithm";
$f->type = \DrSlump\Protobuf::TYPE_ENUM;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$f->reference = '\Vitess\Proto\Query\SplitQueryRequest\Algorithm';
$descriptor->addField($f);
// OPTIONAL BOOL use_split_query_v2 = 8
$f = new \DrSlump\Protobuf\Field();
$f->number = 8;
$f->name = "use_split_query_v2";
$f->type = \DrSlump\Protobuf::TYPE_BOOL;
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
$descriptor->addField($f);
foreach (self::$__extensions as $cb) {
$descriptor->addField($cb(), true);
}
@ -210,10 +244,11 @@ namespace Vitess\Proto\Vtgate {
/**
* Get <split_column> value
*
* @param int $idx
* @return string
*/
public function getSplitColumn(){
return $this->_get(4);
public function getSplitColumn($idx = NULL){
return $this->_get(4, $idx);
}
/**
@ -222,8 +257,27 @@ namespace Vitess\Proto\Vtgate {
* @param string $value
* @return \Vitess\Proto\Vtgate\SplitQueryRequest
*/
public function setSplitColumn( $value){
return $this->_set(4, $value);
public function setSplitColumn( $value, $idx = NULL){
return $this->_set(4, $value, $idx);
}
/**
* Get all elements of <split_column>
*
* @return string[]
*/
public function getSplitColumnList(){
return $this->_get(4);
}
/**
* Add a new element to <split_column>
*
* @param string $value
* @return \Vitess\Proto\Vtgate\SplitQueryRequest
*/
public function addSplitColumn( $value){
return $this->_add(4, $value);
}
/**
@ -262,6 +316,117 @@ namespace Vitess\Proto\Vtgate {
public function setSplitCount( $value){
return $this->_set(5, $value);
}
/**
* Check if <num_rows_per_query_part> has a value
*
* @return boolean
*/
public function hasNumRowsPerQueryPart(){
return $this->_has(6);
}
/**
* Clear <num_rows_per_query_part> value
*
* @return \Vitess\Proto\Vtgate\SplitQueryRequest
*/
public function clearNumRowsPerQueryPart(){
return $this->_clear(6);
}
/**
* Get <num_rows_per_query_part> value
*
* @return int
*/
public function getNumRowsPerQueryPart(){
return $this->_get(6);
}
/**
* Set <num_rows_per_query_part> value
*
* @param int $value
* @return \Vitess\Proto\Vtgate\SplitQueryRequest
*/
public function setNumRowsPerQueryPart( $value){
return $this->_set(6, $value);
}
/**
* Check if <algorithm> has a value
*
* @return boolean
*/
public function hasAlgorithm(){
return $this->_has(7);
}
/**
* Clear <algorithm> value
*
* @return \Vitess\Proto\Vtgate\SplitQueryRequest
*/
public function clearAlgorithm(){
return $this->_clear(7);
}
/**
* Get <algorithm> value
*
* @return int - \Vitess\Proto\Query\SplitQueryRequest\Algorithm
*/
public function getAlgorithm(){
return $this->_get(7);
}
/**
* Set <algorithm> value
*
* @param int - \Vitess\Proto\Query\SplitQueryRequest\Algorithm $value
* @return \Vitess\Proto\Vtgate\SplitQueryRequest
*/
public function setAlgorithm( $value){
return $this->_set(7, $value);
}
/**
* Check if <use_split_query_v2> has a value
*
* @return boolean
*/
public function hasUseSplitQueryV2(){
return $this->_has(8);
}
/**
* Clear <use_split_query_v2> value
*
* @return \Vitess\Proto\Vtgate\SplitQueryRequest
*/
public function clearUseSplitQueryV2(){
return $this->_clear(8);
}
/**
* Get <use_split_query_v2> value
*
* @return boolean
*/
public function getUseSplitQueryV2(){
return $this->_get(8);
}
/**
* Set <use_split_query_v2> value
*
* @param boolean $value
* @return \Vitess\Proto\Vtgate\SplitQueryRequest
*/
public function setUseSplitQueryV2( $value){
return $this->_set(8, $value);
}
}
}

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

@ -204,13 +204,15 @@ class VTGateConn
return new VTGateTx($this->client, $response->getSession());
}
// TODO(erez): Migrate to SplitQueryV2 after it's stable.
public function splitQuery(Context $ctx, $keyspace, $query, array $bind_vars, $split_column, $split_count)
{
$request = new Proto\Vtgate\SplitQueryRequest();
$request->setKeyspace($keyspace);
$request->setQuery(ProtoUtils::BoundQuery($query, $bind_vars));
$request->setSplitColumn($split_column);
$request->addSplitColumn($split_column);
$request->setSplitCount($split_count);
$request->setUseSplitQueryV2(false);
if ($ctx->getCallerId()) {
$request->setCallerId($ctx->getCallerId());
}

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

@ -288,15 +288,37 @@ message RollbackRequest {
// RollbackResponse is the returned value from Rollback
message RollbackResponse {}
// SplitQueryRequest is the payload for SplitQuery
// SplitQueryRequest is the payload for SplitQuery sent by VTGate to a VTTablet.
// See vtgate.SplitQueryRequest for more details.
message SplitQueryRequest {
vtrpc.CallerID effective_caller_id = 1;
VTGateCallerID immediate_caller_id = 2;
Target target = 3;
BoundQuery query = 4;
string split_column = 5;
repeated string split_column = 5;
// Exactly one of the following must be nonzero.
int64 split_count = 6;
int64 num_rows_per_query_part = 8;
int64 session_id = 7;
enum Algorithm {
EQUAL_SPLITS = 0;
FULL_SCAN = 1;
}
Algorithm algorithm = 9;
// Whether to use the new split-query code
// that supports multiple split-columns and
// the FULL_SCAN algorithm.
// This is a temporary field which aids
// in the migration of SplitQuery to the new
// code.
// TODO(erez): Remove this field after the migration
// to the SplitQuery version 2.
bool use_split_query_v2 = 10;
}
// QuerySplit represents one query to execute on the tablet

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

@ -41,6 +41,9 @@ message ExecuteRequest {
// not_in_transaction is deprecated and should not be used.
bool not_in_transaction = 5;
// keyspace to target the query to.
string keyspace = 6;
}
// ExecuteResponse is the returned value from Execute.
@ -345,6 +348,9 @@ message StreamExecuteRequest {
// tablet_type is the type of tablets that this query is targeted to.
topodata.TabletType tablet_type = 3;
// keyspace to target the query to.
string keyspace = 4;
}
// StreamExecuteResponse is the returned value from StreamExecute.
@ -480,6 +486,22 @@ message RollbackResponse {
}
// SplitQueryRequest is the payload to SplitQuery.
//
// SplitQuery takes a "SELECT" query and generates a list of queries called
// "query-parts". Each query-part consists of the original query with an
// added WHERE clause that restricts the query-part to operate only on
// rows whose values in the the columns listed in the "split_column" field
// of the request (see below) are in a particular range.
//
// It is guaranteed that the set of rows obtained from
// executing each query-part on a database snapshot
// and merging (without deduping) the results is equal to the set of rows
// obtained from executing the original query on the same snapshot
// with the rows containing NULL values in any of the split_column's excluded.
//
// This is typically called by the MapReduce master when reading from Vitess.
// There it's desirable that the sets of rows returned by the query-parts
// have roughly the same size.
message SplitQueryRequest {
// caller_id identifies the caller. This is the effective caller ID,
// set by the application to further identify the caller.
@ -488,14 +510,77 @@ message SplitQueryRequest {
// keyspace to target the query to.
string keyspace = 2;
// query is the query and bind variables to produce splits for.
// The query and bind variables to produce splits for.
// The given query must be a simple query of the form
// SELECT <cols> FROM <table> WHERE <filter>.
// It must not contain subqueries nor any of the keywords
// JOIN, GROUP BY, ORDER BY, LIMIT, DISTINCT.
// Furthermore, <table> must be a single concrete table.
// It cannot be a view.
query.BoundQuery query = 3;
// split_column is an optional hint on the column to use to split the query.
string split_column = 4;
// Each generated query-part will be restricted to rows whose values
// in the columns listed in this field are in a particular range.
// The list of columns named here must be a prefix of the list of
// columns defining some index or primary key of the table
// referenced in 'query'. For many tables using the primary key columns
// (in order) is sufficient and this is the default if this field is omitted.
// See the comment on the 'algorithm' field for more restrictions and
// information.
repeated string split_column = 4;
// split_count describes how many splits we want for this query.
// You can specify either an estimate of the number of query-parts to
// generate or an estimate of the number of rows each query-part should
// return.
// Thus, exactly one of split_count or num_rows_per_query_part
// should be nonzero.
// The non-given parameter is calculated from the given parameter
// using the formula: split_count * num_rows_per_query_pary = table_size,
// where table_size is an approximation of the number of rows in the
// table.
// Note that if "split_count" is given it is regarded as an estimate.
// The number of query-parts returned may differ slightly (in particular,
// if it's not a whole multiple of the number of vitess shards).
int64 split_count = 5;
int64 num_rows_per_query_part = 6;
// The algorithm to use to split the query. The split algorithm is performed
// on each database shard in parallel. The lists of query-parts generated
// by the shards are merged and returned to the caller.
// Two algorithms are supported:
// EQUAL_SPLITS
// If this algorithm is used then only one split_column is allowed.
// Additionally, the split_column must have numeric type (integral or
// floating point). The algorithm works by taking the interval [min, max],
// where min and max are the minimum and maximum values of of the
// split_column column in the table-shard, respectively, and
// partitioning it into split_count sub-intervals of equal size.
// The added WHERE clause of each query-part restricts that part to rows
// whose value in split_column belongs to a particular sub-interval.
// This is fast, but requires that the distribution of values of
// split_column be uniform in [min, max], for the number of rows
// returned by each query part to be roughly the same.
// FULL_SCAN
// If this algorithm is used then the split_column must be the primary key
// columns (in order).
// This algorithm performs a full-scan of the table-shard referenced
// in 'query' to get "boundary" rows that are num_rows_per_query_part
// apart when the table is ordered by the columns listed in
// 'split_column'. It then restricts each query-part to the rows
// located between two successive boundary rows.
// This algorithm supports multiple split_column's of any type,
// but is slower than EQUAL_SPLITS.
query.SplitQueryRequest.Algorithm algorithm = 7;
// Whether to use the new split-query code
// that supports multiple split-columns and
// the FULL_SCAN algorithm.
// This is a temporary field which aids
// in the migration of SplitQuery to the new
// code.
// TODO(erez): Remove this field after the migration
// to the SplitQuery version 2.
bool use_split_query_v2 = 8;
}
// SplitQueryResponse is the returned value from SplitQuery.
@ -518,7 +603,8 @@ message SplitQueryResponse {
// query is the query and bind variables to execute.
query.BoundQuery query = 1;
// key_range_part is set if the query should be executed by ExecuteKeyRanges.
// key_range_part is set if the query should be executed by
// ExecuteKeyRanges.
KeyRangePart key_range_part = 2;
// shard_part is set if the query should be executed by ExecuteShards.

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -126,7 +126,7 @@ vschema = '''{
"Owner": "vt_music"
}
},
"Classes": {
"Tables": {
"vt_user": {
"ColVindexes": [
{
@ -203,29 +203,19 @@ vschema = '''{
}
]
}
},
"Tables": {
"vt_user": "vt_user",
"vt_user2": "vt_user2",
"vt_user_extra": "vt_user_extra",
"vt_music": "vt_music",
"vt_music_extra": "vt_music_extra",
"join_user": "join_user",
"join_user_extra": "join_user_extra"
}
},
"lookup": {
"Sharded": false,
"Classes" : {
"seq": {
"Type": "Sequence"
}
},
"Tables": {
"vt_user_seq": "seq",
"vt_music_seq": "seq",
"music_user_map": "",
"name_user2_map": ""
"vt_user_seq": {
"Type": "Sequence"
},
"vt_music_seq": {
"Type": "Sequence"
},
"music_user_map": {},
"name_user2_map": {}
}
}
}

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

@ -4,9 +4,12 @@
# It should be run from $VTTOP.
# Dependencies:
# - PHP 5.3+
# - PHP 5.5+
# - PEAR
# - protoc-gen-php: http://www.grpc.io/docs/installation/php.html
# - gem (ruby)
# - protoc (protobuf)
# - protoc-gen-php:
# https://github.com/grpc/grpc/tree/master/src/php#php-protobuf-compiler
set -e