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

Create Region JSON Vindex #5806

Merged
merged 19 commits into from Mar 20, 2020
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
5579aed
Added (broken) region Vindex from https://github.com/planetscale/vite…
RyanLeonardSpruce Feb 5, 2020
8266a34
Implemented changes similar to https://github.com/vitessio/vitess/com…
RyanLeonardSpruce Feb 5, 2020
c9369bc
Implemented changes similar to https://github.com/vitessio/vitess/com…
RyanLeonardSpruce Feb 5, 2020
27dab6b
Added regionBytes field.
RyanLeonardSpruce Feb 5, 2020
d834206
Removed extra import. NeedVCursor -> NeedsVCursor
RyanLeonardSpruce Feb 5, 2020
6571605
Copied 'Verify' from https://github.com/vitessio/vitess/commit/a09139…
RyanLeonardSpruce Feb 5, 2020
dde3a3f
Import bytes.
RyanLeonardSpruce Feb 5, 2020
99c3b2b
bytes -> byte
RyanLeonardSpruce Feb 5, 2020
d9fe561
Updated formatting.
RyanLeonardSpruce Feb 6, 2020
c73e8d4
Renamed 'region_vindex' -> 'region_json'.
RyanLeonardSpruce Feb 7, 2020
57a37ef
Updated copyright, removed log messages.
RyanLeonardSpruce Feb 7, 2020
54189ea
Added line of code accidentally deleted with logs.
RyanLeonardSpruce Feb 7, 2020
c8e7adc
Typo staisfies -> satisfies, nit: region_experimental -> RegionExperi…
RyanLeonardSpruce Feb 7, 2020
df13dcb
Added 'RegionExperimental' wrapping back. Removed 'Verify' function.
RyanLeonardSpruce Feb 7, 2020
392c92a
Fixed formatting.
RyanLeonardSpruce Feb 7, 2020
57a2bad
Removed unused import.
RyanLeonardSpruce Feb 7, 2020
4fb7697
Revert "Added 'RegionExperimental' wrapping back. Removed 'Verify' f…
RyanLeonardSpruce Feb 10, 2020
23fe963
Added bytes back in.
RyanLeonardSpruce Feb 10, 2020
ddbabb1
Updated RegionJson description with comments from @sougou
RyanLeonardSpruce Mar 5, 2020
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
141 changes: 141 additions & 0 deletions go/vt/vtgate/vindexes/region_json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
Copyright 2020 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package vindexes

import (
"bytes"
"encoding/binary"
"encoding/json"
"io/ioutil"

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

var (
_ MultiColumn = (*RegionJson)(nil)
)

func init() {
Register("region_json", NewRegionJson)
}

// RegionMap is used to store mapping of country to region
type RegionMap map[string]uint64

// RegionJson is a multi-column unique vindex
// The first column is used to lookup the prefix part of the keyspace id, the second column is hashed,
// and the two values are combined to produce the keyspace id.
// RegionJson can be used for geo-partitioning because the first column can denote a region,
// and it will dictate the shard range for that region.
type RegionJson struct {
RyanLeonardSpruce marked this conversation as resolved.
Show resolved Hide resolved
name string
regionMap RegionMap
regionBytes int
}

// NewRegionJson creates a RegionJson vindex.
// The supplied map requires all the fields of "RegionExperimental".
// Additionally, it requires a region_map argument representing the path to a json file
// containing a map of country to region.
func NewRegionJson(name string, m map[string]string) (Vindex, error) {
rmPath := m["region_map"]
rmap := make(map[string]uint64)
data, err := ioutil.ReadFile(rmPath)
if err != nil {
return nil, err
}
log.Infof("Loaded Region map from: %s", rmPath)
err = json.Unmarshal(data, &rmap)
if err != nil {
return nil, err
}

return &RegionJson{
name: name,
regionMap: rmap,
}, nil
}

// String returns the name of the vindex.
func (rv *RegionJson) String() string {
return rv.name
}

// Cost returns the cost of this index as 1.
func (rv *RegionJson) Cost() int {
return 1
}

// IsUnique returns true since the Vindex is unique.
func (rv *RegionJson) IsUnique() bool {
return true
}

// Map satisfies MultiColumn.
func (rv *RegionJson) Map(vcursor VCursor, rowsColValues [][]sqltypes.Value) ([]key.Destination, error) {
destinations := make([]key.Destination, 0, len(rowsColValues))
for _, row := range rowsColValues {
if len(row) != 2 {
destinations = append(destinations, key.DestinationNone{})
continue
}
// Compute hash.
hn, err := sqltypes.ToUint64(row[0])
if err != nil {
destinations = append(destinations, key.DestinationNone{})
continue
}
h := vhash(hn)

rn, ok := rv.regionMap[row[1].ToString()]
if !ok {
destinations = append(destinations, key.DestinationNone{})
continue
}
r := make([]byte, 2)
binary.BigEndian.PutUint16(r, uint16(rn))

// Concatenate and add to destinations.
if rv.regionBytes == 1 {
r = r[1:]
}
dest := append(r, h...)
destinations = append(destinations, key.DestinationKeyspaceID(dest))
}
return destinations, nil
}

// Verify satisfies MultiColumn
func (rv *RegionJson) Verify(vcursor VCursor, rowsColValues [][]sqltypes.Value, ksids [][]byte) ([]bool, error) {
result := make([]bool, len(rowsColValues))
destinations, _ := rv.Map(vcursor, rowsColValues)
for i, dest := range destinations {
destksid, ok := dest.(key.DestinationKeyspaceID)
if !ok {
continue
}
result[i] = bytes.Equal([]byte(destksid), ksids[i])
}
return result, nil
}

// NeedVCursor satisfies the Vindex interface.
func (rv *RegionJson) NeedsVCursor() bool {
return false
}