Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add monetate_crc32 multi-column vindex. #1

Merged
merged 1 commit into from
Sep 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions go/vt/vtgate/vindexes/monetate_crc32.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
Copyright 2023 Monetate, Inc.
*/

package vindexes

import (
"bytes"
"context"
"encoding/binary"
"hash/crc32"
"strings"

"vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/vt/key"
vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
"vitess.io/vitess/go/vt/vterrors"
)

var _ MultiColumn = (*MonetateCRC32)(nil)

type MonetateCRC32 struct {
name string
}

// NewMonetateCRC32 creates a new MonetateCRC32.
func NewMonetateCRC32(name string, m map[string]string) (Vindex, error) {
return &MonetateCRC32{name: name}, nil
}

func (m *MonetateCRC32) String() string {
return m.name
}

func (m *MonetateCRC32) Cost() int {
return 1
}

func (m *MonetateCRC32) IsUnique() bool {
return true
}

func (m *MonetateCRC32) NeedsVCursor() bool {
return false
}

func (m *MonetateCRC32) Map(ctx context.Context, vcursor VCursor, rowsColValues [][]sqltypes.Value) ([]key.Destination, error) {
out := make([]key.Destination, 0, len(rowsColValues))
for _, colValues := range rowsColValues {
ksid, err := ChecksumValues(colValues)
if err != nil {
out = append(out, key.DestinationNone{})
continue
}
out = append(out, key.DestinationKeyspaceID(ksid))
}
return out, nil
}

func (m *MonetateCRC32) Verify(ctx context.Context, vcursor VCursor, rowsColValues [][]sqltypes.Value, ksids [][]byte) ([]bool, error) {
out := make([]bool, 0, len(rowsColValues))
for idx, colValues := range rowsColValues {
ksid, err := ChecksumValues(colValues)
if err != nil {
return nil, err
}
out = append(out, bytes.Equal(ksid, ksids[idx]))
}
return out, nil
}

func (m *MonetateCRC32) PartialVindex() bool {
return false
}

func ChecksumValues(colValues []sqltypes.Value) ([]byte, error) {
// concat string values of columns, separated by slashes
var parts []string
for _, colVal := range colValues {
if !(colVal.IsIntegral() || colVal.IsText() || colVal.IsBinary()) {
return nil, vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "invalid monetate vindex value")
}
parts = append(parts, colVal.ToString())
}
var shardKey = strings.Join(parts, "/")
var checksum = crc32.ChecksumIEEE([]byte(shardKey))
var vshard = checksum % 1048576 // 20 bit vshard id

var hashed [4]byte
binary.BigEndian.PutUint32(hashed[:], vshard<<12)
return hashed[:], nil
}

func init() {
Register("monetate_crc32", NewMonetateCRC32)
}
41 changes: 41 additions & 0 deletions go/vt/vtgate/vindexes/monetate_crc32_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
Copyright 2023 Monetate, Inc.
*/

package vindexes

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/vt/key"
)

func TestMonetateCRC32Map(t *testing.T) {
vindex, err := CreateVindex("monetate_crc32", "monetate", map[string]string{})
require.NoError(t, err)
mutiCol := vindex.(MultiColumn)

got, err := mutiCol.Map(context.Background(), nil, [][]sqltypes.Value{{
// visitor shard key
sqltypes.NewInt64(1), sqltypes.NewInt64(2), sqltypes.NewInt64(3),
}, {
// customer shard key
sqltypes.NewInt64(1), sqltypes.NewVarBinary("customer_id"),
}, {
// customer shard key, invalid customer id as null
sqltypes.NewInt64(1), sqltypes.NULL,
}})
assert.NoError(t, err)

want := []key.Destination{
key.DestinationKeyspaceID("\x1b\x1c\x60\x00"),
key.DestinationKeyspaceID("\xc4\x4b\xe0\x00"),
key.DestinationNone{},
}
assert.Equal(t, want, got)
}