vitess.io/vitess@v0.16.2/go/vt/vtgate/vindexes/reverse_bits.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 "bytes" 21 "context" 22 "encoding/binary" 23 "encoding/hex" 24 "fmt" 25 "math/bits" 26 27 "vitess.io/vitess/go/vt/vtgate/evalengine" 28 29 "vitess.io/vitess/go/sqltypes" 30 "vitess.io/vitess/go/vt/key" 31 ) 32 33 var ( 34 _ SingleColumn = (*ReverseBits)(nil) 35 _ Reversible = (*ReverseBits)(nil) 36 _ Hashing = (*ReverseBits)(nil) 37 ) 38 39 // ReverseBits defines vindex that reverses the bits of a number. 40 // It's Unique, Reversible and Functional. 41 type ReverseBits struct { 42 name string 43 } 44 45 // NewReverseBits creates a new ReverseBits. 46 func NewReverseBits(name string, m map[string]string) (Vindex, error) { 47 return &ReverseBits{name: name}, nil 48 } 49 50 // String returns the name of the vindex. 51 func (vind *ReverseBits) String() string { 52 return vind.name 53 } 54 55 // Cost returns the cost of this index as 1. 56 func (vind *ReverseBits) Cost() int { 57 return 1 58 } 59 60 // IsUnique returns true since the Vindex is unique. 61 func (vind *ReverseBits) IsUnique() bool { 62 return true 63 } 64 65 // NeedsVCursor satisfies the Vindex interface. 66 func (vind *ReverseBits) NeedsVCursor() bool { 67 return false 68 } 69 70 // Map returns the corresponding KeyspaceId values for the given ids. 71 func (vind *ReverseBits) Map(ctx context.Context, vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) { 72 out := make([]key.Destination, 0, len(ids)) 73 for _, id := range ids { 74 num, err := vind.Hash(id) 75 if err != nil { 76 out = append(out, key.DestinationNone{}) 77 continue 78 } 79 out = append(out, key.DestinationKeyspaceID(num)) 80 } 81 return out, nil 82 } 83 84 // Verify returns true if ids maps to ksids. 85 func (vind *ReverseBits) Verify(ctx context.Context, vcursor VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, error) { 86 out := make([]bool, 0, len(ids)) 87 for i, id := range ids { 88 num, err := vind.Hash(id) 89 if err != nil { 90 return nil, err 91 } 92 out = append(out, bytes.Equal(num, ksids[i])) 93 } 94 return out, nil 95 } 96 97 // ReverseMap returns the ids from ksids. 98 func (vind *ReverseBits) ReverseMap(_ VCursor, ksids [][]byte) ([]sqltypes.Value, error) { 99 reverseIds := make([]sqltypes.Value, 0, len(ksids)) 100 for _, keyspaceID := range ksids { 101 val, err := unreverse(keyspaceID) 102 if err != nil { 103 return reverseIds, err 104 } 105 reverseIds = append(reverseIds, sqltypes.NewUint64(val)) 106 } 107 return reverseIds, nil 108 } 109 110 func (vind *ReverseBits) Hash(id sqltypes.Value) ([]byte, error) { 111 num, err := evalengine.ToUint64(id) 112 if err != nil { 113 return nil, err 114 } 115 return reverse(num), nil 116 } 117 118 func init() { 119 Register("reverse_bits", NewReverseBits) 120 } 121 122 func reverse(shardKey uint64) []byte { 123 reversed := make([]byte, 8) 124 binary.BigEndian.PutUint64(reversed, bits.Reverse64(shardKey)) 125 return reversed 126 } 127 128 func unreverse(k []byte) (uint64, error) { 129 if len(k) != 8 { 130 return 0, fmt.Errorf("invalid keyspace id: %v", hex.EncodeToString(k)) 131 } 132 return bits.Reverse64(binary.BigEndian.Uint64(k)), nil 133 }