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  }