vitess.io/vitess@v0.16.2/go/vt/vtgate/vindexes/vindex.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package vindexes 18 19 import ( 20 "context" 21 "fmt" 22 23 "vitess.io/vitess/go/sqltypes" 24 "vitess.io/vitess/go/vt/key" 25 "vitess.io/vitess/go/vt/sqlparser" 26 "vitess.io/vitess/go/vt/vterrors" 27 28 querypb "vitess.io/vitess/go/vt/proto/query" 29 vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" 30 vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" 31 ) 32 33 // This file defines interfaces and registration for vindexes. 34 35 type ( 36 // A VCursor is an interface that allows you to execute queries 37 // in the current context and session of a VTGate request. Vindexes 38 // can use this interface to execute lookup queries. 39 VCursor interface { 40 Execute(ctx context.Context, method string, query string, bindvars map[string]*querypb.BindVariable, rollbackOnError bool, co vtgatepb.CommitOrder) (*sqltypes.Result, error) 41 ExecuteKeyspaceID(ctx context.Context, keyspace string, ksid []byte, query string, bindVars map[string]*querypb.BindVariable, rollbackOnError, autocommit bool) (*sqltypes.Result, error) 42 InTransactionAndIsDML() bool 43 LookupRowLockShardSession() vtgatepb.CommitOrder 44 } 45 46 // Vindex defines the interface required to register a vindex. 47 Vindex interface { 48 // String returns the name of the Vindex instance. 49 // It's used for testing and diagnostics. Use pointer 50 // comparison to see if two objects refer to the same 51 // Vindex. 52 String() string 53 54 // Cost is used by planbuilder to prioritize vindexes. 55 // The cost can be 0 if the id is basically a keyspace id. 56 // The cost can be 1 if the id can be hashed to a keyspace id. 57 // The cost can be 2 or above if the id needs to be looked up 58 // from an external data source. These guidelines are subject 59 // to change in the future. 60 Cost() int 61 62 // IsUnique returns true if the Vindex is unique. 63 // A Unique Vindex is allowed to return non-unique values like 64 // a keyrange. This is in situations where the vindex does not 65 // have enough information to map to a keyspace id. If so, such 66 // a vindex cannot be primary. 67 IsUnique() bool 68 69 // NeedsVCursor returns true if the Vindex makes calls into the 70 // VCursor. Such vindexes cannot be used by vreplication. 71 NeedsVCursor() bool 72 } 73 74 // SingleColumn defines the interface for a single column vindex. 75 SingleColumn interface { 76 Vindex 77 // Map can map ids to key.Destination objects. 78 // If the Vindex is unique, each id would map to either 79 // a KeyRange, or a single KeyspaceID. 80 // If the Vindex is non-unique, each id would map to either 81 // a KeyRange, or a list of KeyspaceID. 82 Map(ctx context.Context, vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) 83 84 // Verify returns true for every id that successfully maps to the 85 // specified keyspace id. 86 Verify(ctx context.Context, vcursor VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, error) 87 } 88 89 // MultiColumn defines the interface for a multi-column vindex. 90 MultiColumn interface { 91 Vindex 92 Map(ctx context.Context, vcursor VCursor, rowsColValues [][]sqltypes.Value) ([]key.Destination, error) 93 Verify(ctx context.Context, vcursor VCursor, rowsColValues [][]sqltypes.Value, ksids [][]byte) ([]bool, error) 94 // PartialVindex returns true if subset of columns can be passed in to the vindex Map and Verify function. 95 PartialVindex() bool 96 } 97 98 // Hashing defined the interface for the vindexes that export the Hash function to be used by multi-column vindex. 99 Hashing interface { 100 Hash(id sqltypes.Value) ([]byte, error) 101 } 102 // A Reversible vindex is one that can perform a 103 // reverse lookup from a keyspace id to an id. This 104 // is optional. If present, VTGate can use it to 105 // fill column values based on the target keyspace id. 106 // Reversible is supported only for SingleColumn vindexes. 107 Reversible interface { 108 SingleColumn 109 ReverseMap(vcursor VCursor, ks [][]byte) ([]sqltypes.Value, error) 110 } 111 112 // A Prefixable vindex is one that maps the prefix of a id to a keyspace range 113 // instead of a single keyspace id. It's being used to reduced the fan out for 114 // 'LIKE' expressions. 115 Prefixable interface { 116 SingleColumn 117 PrefixVindex() SingleColumn 118 } 119 120 // A Lookup vindex is one that needs to lookup 121 // a previously stored map to compute the keyspace 122 // id from an id. This means that the creation of 123 // a lookup vindex entry requires a keyspace id as 124 // input. 125 // A Lookup vindex need not be unique because the 126 // keyspace_id, which must be supplied, can be used 127 // to determine the target shard for an insert operation. 128 Lookup interface { 129 // Create creates an association between ids and ksids. If ignoreMode 130 // is true, then the Create should ignore dup key errors. 131 Create(ctx context.Context, vcursor VCursor, rowsColValues [][]sqltypes.Value, ksids [][]byte, ignoreMode bool) error 132 133 Delete(ctx context.Context, vcursor VCursor, rowsColValues [][]sqltypes.Value, ksid []byte) error 134 135 // Update replaces the mapping of old values with new values for a keyspace id. 136 Update(ctx context.Context, vcursor VCursor, oldValues []sqltypes.Value, ksid []byte, newValues []sqltypes.Value) error 137 } 138 139 // LookupPlanable are for lookup vindexes where we can extract the lookup query at plan time 140 LookupPlanable interface { 141 String() string 142 Query() (selQuery string, arguments []string) 143 MapResult(ids []sqltypes.Value, results []*sqltypes.Result) ([]key.Destination, error) 144 AllowBatch() bool 145 GetCommitOrder() vtgatepb.CommitOrder 146 AutoCommitEnabled() bool 147 } 148 149 // LookupBackfill interfaces all lookup vindexes that can backfill rows, such as LookupUnique. 150 LookupBackfill interface { 151 IsBackfilling() bool 152 } 153 154 // WantOwnerInfo defines the interface that a vindex must 155 // satisfy to request info about the owner table. This information can 156 // be used to query the owner's table for the owning row's presence. 157 WantOwnerInfo interface { 158 SetOwnerInfo(keyspace, table string, cols []sqlparser.IdentifierCI) error 159 } 160 161 // A NewVindexFunc is a function that creates a Vindex based on the 162 // properties specified in the input map. Every vindex must 163 // register a NewVindexFunc under a unique vindexType. 164 NewVindexFunc func(string, map[string]string) (Vindex, error) 165 ) 166 167 var registry = make(map[string]NewVindexFunc) 168 169 // Register registers a vindex under the specified vindexType. 170 // A duplicate vindexType will generate a panic. 171 // New vindexes will be created using these functions at the 172 // time of vschema loading. 173 func Register(vindexType string, newVindexFunc NewVindexFunc) { 174 if _, ok := registry[vindexType]; ok { 175 panic(fmt.Sprintf("%s is already registered", vindexType)) 176 } 177 registry[vindexType] = newVindexFunc 178 } 179 180 // CreateVindex creates a vindex of the specified type using the 181 // supplied params. The type must have been previously registered. 182 func CreateVindex(vindexType, name string, params map[string]string) (Vindex, error) { 183 f, ok := registry[vindexType] 184 if !ok { 185 return nil, fmt.Errorf("vindexType %q not found", vindexType) 186 } 187 return f(name, params) 188 } 189 190 // Map invokes the Map implementation supplied by the vindex. 191 func Map(ctx context.Context, vindex Vindex, vcursor VCursor, rowsColValues [][]sqltypes.Value) ([]key.Destination, error) { 192 switch vindex := vindex.(type) { 193 case MultiColumn: 194 return vindex.Map(ctx, vcursor, rowsColValues) 195 case SingleColumn: 196 return vindex.Map(ctx, vcursor, firstColsOnly(rowsColValues)) 197 } 198 return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "vindex '%T' does not have Map function", vindex) 199 } 200 201 // Verify invokes the Verify implementation supplied by the vindex. 202 func Verify(ctx context.Context, vindex Vindex, vcursor VCursor, rowsColValues [][]sqltypes.Value, ksids [][]byte) ([]bool, error) { 203 switch vindex := vindex.(type) { 204 case MultiColumn: 205 return vindex.Verify(ctx, vcursor, rowsColValues, ksids) 206 case SingleColumn: 207 return vindex.Verify(ctx, vcursor, firstColsOnly(rowsColValues), ksids) 208 } 209 return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "vindex '%T' does not have Verify function", vindex) 210 } 211 212 func firstColsOnly(rowsColValues [][]sqltypes.Value) []sqltypes.Value { 213 firstCols := make([]sqltypes.Value, 0, len(rowsColValues)) 214 for _, val := range rowsColValues { 215 firstCols = append(firstCols, val[0]) 216 } 217 return firstCols 218 }