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  }