vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletmanager/vreplication/external_connector.go (about) 1 /* 2 Copyright 2020 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package vreplication 18 19 import ( 20 "sync" 21 22 "context" 23 24 "vitess.io/vitess/go/sqltypes" 25 "vitess.io/vitess/go/vt/dbconfigs" 26 "vitess.io/vitess/go/vt/grpcclient" 27 binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" 28 querypb "vitess.io/vitess/go/vt/proto/query" 29 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 30 vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" 31 "vitess.io/vitess/go/vt/vterrors" 32 "vitess.io/vitess/go/vt/vttablet/queryservice" 33 "vitess.io/vitess/go/vt/vttablet/tabletconn" 34 "vitess.io/vitess/go/vt/vttablet/tabletserver/schema" 35 "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" 36 "vitess.io/vitess/go/vt/vttablet/tabletserver/vstreamer" 37 ) 38 39 var ( 40 _ VStreamerClient = (*mysqlConnector)(nil) 41 _ VStreamerClient = (*tabletConnector)(nil) 42 ) 43 44 // VStreamerClient exposes the core interface of a vstreamer 45 type VStreamerClient interface { 46 Open(context.Context) error 47 Close(context.Context) error 48 49 // VStream streams VReplication events based on the specified filter. 50 VStream(ctx context.Context, startPos string, tablePKs []*binlogdatapb.TableLastPK, filter *binlogdatapb.Filter, send func([]*binlogdatapb.VEvent) error) error 51 52 // VStreamRows streams rows of a table from the specified starting point. 53 VStreamRows(ctx context.Context, query string, lastpk *querypb.QueryResult, send func(*binlogdatapb.VStreamRowsResponse) error) error 54 } 55 56 type externalConnector struct { 57 mu sync.Mutex 58 dbconfigs map[string]*dbconfigs.DBConfigs 59 connectors map[string]*mysqlConnector 60 } 61 62 func newExternalConnector(dbcfgs map[string]*dbconfigs.DBConfigs) *externalConnector { 63 return &externalConnector{ 64 dbconfigs: dbcfgs, 65 connectors: make(map[string]*mysqlConnector), 66 } 67 } 68 69 func (ec *externalConnector) Close() { 70 for _, c := range ec.connectors { 71 c.shutdown() 72 } 73 ec.connectors = make(map[string]*mysqlConnector) 74 } 75 76 func (ec *externalConnector) Get(name string) (*mysqlConnector, error) { 77 ec.mu.Lock() 78 defer ec.mu.Unlock() 79 if c, ok := ec.connectors[name]; ok { 80 return c, nil 81 } 82 83 // Construct 84 config := tabletenv.NewDefaultConfig() 85 config.DB = ec.dbconfigs[name] 86 if config.DB == nil { 87 return nil, vterrors.Errorf(vtrpcpb.Code_NOT_FOUND, "external mysqlConnector %v not found", name) 88 } 89 c := &mysqlConnector{} 90 c.env = tabletenv.NewEnv(config, name) 91 c.se = schema.NewEngine(c.env) 92 c.vstreamer = vstreamer.NewEngine(c.env, nil, c.se, nil, "") 93 c.vstreamer.InitDBConfig("", "") 94 c.se.InitDBConfig(c.env.Config().DB.AllPrivsWithDB()) 95 96 // Open 97 if err := c.se.Open(); err != nil { 98 return nil, vterrors.Wrapf(err, "external mysqlConnector: %v", name) 99 } 100 c.vstreamer.Open() 101 102 // Register 103 ec.connectors[name] = c 104 return c, nil 105 } 106 107 //----------------------------------------------------------- 108 109 type mysqlConnector struct { 110 env tabletenv.Env 111 se *schema.Engine 112 vstreamer *vstreamer.Engine 113 } 114 115 func (c *mysqlConnector) shutdown() { 116 c.vstreamer.Close() 117 c.se.Close() 118 } 119 120 func (c *mysqlConnector) Open(ctx context.Context) error { 121 return nil 122 } 123 124 func (c *mysqlConnector) Close(ctx context.Context) error { 125 return nil 126 } 127 128 func (c *mysqlConnector) VStream(ctx context.Context, startPos string, tablePKs []*binlogdatapb.TableLastPK, filter *binlogdatapb.Filter, send func([]*binlogdatapb.VEvent) error) error { 129 return c.vstreamer.Stream(ctx, startPos, tablePKs, filter, send) 130 } 131 132 func (c *mysqlConnector) VStreamRows(ctx context.Context, query string, lastpk *querypb.QueryResult, send func(*binlogdatapb.VStreamRowsResponse) error) error { 133 var row []sqltypes.Value 134 if lastpk != nil { 135 r := sqltypes.Proto3ToResult(lastpk) 136 if len(r.Rows) != 1 { 137 return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unexpected lastpk input: %v", lastpk) 138 } 139 row = r.Rows[0] 140 } 141 return c.vstreamer.StreamRows(ctx, query, row, send) 142 } 143 144 //----------------------------------------------------------- 145 146 type tabletConnector struct { 147 tablet *topodatapb.Tablet 148 target *querypb.Target 149 qs queryservice.QueryService 150 } 151 152 func newTabletConnector(tablet *topodatapb.Tablet) *tabletConnector { 153 return &tabletConnector{ 154 tablet: tablet, 155 target: &querypb.Target{ 156 Keyspace: tablet.Keyspace, 157 Shard: tablet.Shard, 158 TabletType: tablet.Type, 159 }, 160 } 161 } 162 163 func (tc *tabletConnector) Open(ctx context.Context) error { 164 var err error 165 tc.qs, err = tabletconn.GetDialer()(tc.tablet, grpcclient.FailFast(true)) 166 return err 167 } 168 169 func (tc *tabletConnector) Close(ctx context.Context) error { 170 return tc.qs.Close(ctx) 171 } 172 173 func (tc *tabletConnector) VStream(ctx context.Context, startPos string, tablePKs []*binlogdatapb.TableLastPK, filter *binlogdatapb.Filter, send func([]*binlogdatapb.VEvent) error) error { 174 req := &binlogdatapb.VStreamRequest{Target: tc.target, Position: startPos, TableLastPKs: tablePKs, Filter: filter} 175 return tc.qs.VStream(ctx, req, send) 176 } 177 178 func (tc *tabletConnector) VStreamRows(ctx context.Context, query string, lastpk *querypb.QueryResult, send func(*binlogdatapb.VStreamRowsResponse) error) error { 179 req := &binlogdatapb.VStreamRowsRequest{Target: tc.target, Query: query, Lastpk: lastpk} 180 return tc.qs.VStreamRows(ctx, req, send) 181 }