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

fix(keyviz): find nearest id if not found #1268

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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
130 changes: 116 additions & 14 deletions pkg/keyvisual/decorator/tidb.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"context"
"encoding/hex"
"fmt"
"sort"
"sync"
"time"

Expand All @@ -24,6 +25,7 @@
EtcdClient: etcdClient,
tidbClient: tidbClient,
SchemaVersion: -1,
tableInOrder: &tableInOrder{},

Check warning on line 28 in pkg/keyvisual/decorator/tidb.go

View check run for this annotation

Codecov / codecov/patch

pkg/keyvisual/decorator/tidb.go#L28

Added line #L28 was not covered by tests
}

lc.Append(fx.Hook{
Expand Down Expand Up @@ -52,14 +54,103 @@
EtcdClient *clientv3.Client

TableMap sync.Map
tableInOrder *tableInOrder
tidbClient *tidb.Client
SchemaVersion int64
TidbAddress []string
}

type tableInOrder struct {
mu sync.RWMutex
tables []*tableDetail
}

// BuildFromTableMap build ordered tables from a table map.
func (inOrder *tableInOrder) buildFromTableMap(m *sync.Map) {
if m == nil {
return
}

Check warning on line 72 in pkg/keyvisual/decorator/tidb.go

View check run for this annotation

Codecov / codecov/patch

pkg/keyvisual/decorator/tidb.go#L71-L72

Added lines #L71 - L72 were not covered by tests

tables := []*tableDetail{}
m.Range(func(key, value interface{}) bool {
t := value.(*tableDetail)
tables = append(tables, t)
return true
})

sort.Sort(&tableSorter{tables: tables})

inOrder.mu.Lock()
defer inOrder.mu.Unlock()
inOrder.tables = tables
}

// FindOne will find first table detail which id is between [fromId, toId).
// Returns nil if not found any.
func (inOrder *tableInOrder) findOne(fromID, toID int64) *tableDetail {
if fromID >= toID {
return nil
}

inOrder.mu.RLock()
defer inOrder.mu.RUnlock()

tLen := len(inOrder.tables)
if tLen == 0 {
return nil
}

pivot := tLen / 2
left := 0
right := tLen
for pivot > left {
prevID := inOrder.tables[pivot-1].ID
id := inOrder.tables[pivot].ID
// find approaching id near the fromId
// table_1 ------- table_3 ------- table_5
// ^
// search table_2
// approaching result: table_3
if prevID < fromID && id >= fromID {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id >= toID?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean out of the range logic in L117-L120?😂

break
}

if id < fromID {
left = pivot
} else {
right = pivot
}
pivot = (left + right) / 2
}

id := inOrder.tables[pivot].ID
if id < fromID || id > toID {
return nil
}

return inOrder.tables[pivot]
}

type tableSorter struct {
tables []*tableDetail
}

func (ts *tableSorter) Len() int {
return len(ts.tables)
}

func (ts *tableSorter) Swap(i, j int) {
ts.tables[i], ts.tables[j] = ts.tables[j], ts.tables[i]
}

func (ts *tableSorter) Less(i, j int) bool {
return ts.tables[i].ID < ts.tables[j].ID
}

type tidbLabeler struct {
TableMap *sync.Map
Buffer model.KeyInfoBuffer
TableMap *sync.Map
tableInOrder *tableInOrder
Buffer model.KeyInfoBuffer
}

func (s *tidbLabelStrategy) ReloadConfig(cfg *config.KeyVisualConfig) {}
Expand All @@ -79,7 +170,8 @@

func (s *tidbLabelStrategy) NewLabeler() Labeler {
return &tidbLabeler{
TableMap: &s.TableMap,
TableMap: &s.TableMap,
tableInOrder: s.tableInOrder,

Check warning on line 174 in pkg/keyvisual/decorator/tidb.go

View check run for this annotation

Codecov / codecov/patch

pkg/keyvisual/decorator/tidb.go#L173-L174

Added lines #L173 - L174 were not covered by tests
}
}

Expand All @@ -105,8 +197,8 @@
// Label will parse the ID information of the table and index.
func (e *tidbLabeler) Label(keys []string) []LabelKey {
labelKeys := make([]LabelKey, len(keys))
for i, key := range keys {
labelKeys[i] = e.label(key)
for i := 1; i < len(keys); i++ {
labelKeys[i-1] = e.label(keys[i-1], keys[i])

Check warning on line 201 in pkg/keyvisual/decorator/tidb.go

View check run for this annotation

Codecov / codecov/patch

pkg/keyvisual/decorator/tidb.go#L200-L201

Added lines #L200 - L201 were not covered by tests
}

if keys[0] == "" {
Expand All @@ -120,30 +212,40 @@
return labelKeys
}

func (e *tidbLabeler) label(key string) (label LabelKey) {
keyBytes := region.Bytes(key)
label.Key = hex.EncodeToString(keyBytes)
keyInfo, _ := e.Buffer.DecodeKey(keyBytes)
func (e *tidbLabeler) label(lKey, rKey string) (label LabelKey) {
lKeyBytes := region.Bytes(lKey)
label.Key = hex.EncodeToString(lKeyBytes)
lKeyInfo, _ := e.Buffer.DecodeKey(lKeyBytes)

Check warning on line 218 in pkg/keyvisual/decorator/tidb.go

View check run for this annotation

Codecov / codecov/patch

pkg/keyvisual/decorator/tidb.go#L215-L218

Added lines #L215 - L218 were not covered by tests

isMeta, tableID := keyInfo.MetaOrTable()
isMeta, lTableID := lKeyInfo.MetaOrTable()

Check warning on line 220 in pkg/keyvisual/decorator/tidb.go

View check run for this annotation

Codecov / codecov/patch

pkg/keyvisual/decorator/tidb.go#L220

Added line #L220 was not covered by tests
if isMeta {
label.Labels = append(label.Labels, "meta")
return
}

var detail *tableDetail
if v, ok := e.TableMap.Load(tableID); ok {
if v, ok := e.TableMap.Load(lTableID); ok {

Check warning on line 227 in pkg/keyvisual/decorator/tidb.go

View check run for this annotation

Codecov / codecov/patch

pkg/keyvisual/decorator/tidb.go#L227

Added line #L227 was not covered by tests
detail = v.(*tableDetail)
label.Labels = append(label.Labels, detail.DB, detail.Name)
} else {
label.Labels = append(label.Labels, fmt.Sprintf("table_%d", tableID))
rKeyBytes := region.Bytes(rKey)
rKeyInfo, _ := e.Buffer.DecodeKey(rKeyBytes)
_, rTableID := rKeyInfo.MetaOrTable()
detail := e.tableInOrder.findOne(lTableID, rTableID)

if detail != nil {
label.Labels = append(label.Labels, detail.DB, detail.Name)
// can't find the row/index info if the table info was came from a range
return
}
label.Labels = append(label.Labels, fmt.Sprintf("table_%d", lTableID))

Check warning on line 241 in pkg/keyvisual/decorator/tidb.go

View check run for this annotation

Codecov / codecov/patch

pkg/keyvisual/decorator/tidb.go#L231-L241

Added lines #L231 - L241 were not covered by tests
}

if isCommonHandle, rowID := keyInfo.RowInfo(); isCommonHandle {
if isCommonHandle, rowID := lKeyInfo.RowInfo(); isCommonHandle {

Check warning on line 244 in pkg/keyvisual/decorator/tidb.go

View check run for this annotation

Codecov / codecov/patch

pkg/keyvisual/decorator/tidb.go#L244

Added line #L244 was not covered by tests
label.Labels = append(label.Labels, "row")
} else if rowID != 0 {
label.Labels = append(label.Labels, fmt.Sprintf("row_%d", rowID))
} else if indexID := keyInfo.IndexInfo(); indexID != 0 {
} else if indexID := lKeyInfo.IndexInfo(); indexID != 0 {

Check warning on line 248 in pkg/keyvisual/decorator/tidb.go

View check run for this annotation

Codecov / codecov/patch

pkg/keyvisual/decorator/tidb.go#L248

Added line #L248 was not covered by tests
if detail == nil {
label.Labels = append(label.Labels, fmt.Sprintf("index_%d", indexID))
} else if name, ok := detail.Indices[indexID]; ok {
Expand Down
2 changes: 2 additions & 0 deletions pkg/keyvisual/decorator/tidb_requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@
}
}

s.tableInOrder.buildFromTableMap(&s.TableMap)

Check warning on line 108 in pkg/keyvisual/decorator/tidb_requests.go

View check run for this annotation

Codecov / codecov/patch

pkg/keyvisual/decorator/tidb_requests.go#L107-L108

Added lines #L107 - L108 were not covered by tests
// update schema version
if updateSuccess {
s.SchemaVersion = schemaVersion
Expand Down
48 changes: 48 additions & 0 deletions pkg/keyvisual/decorator/tidb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,57 @@
package decorator

import (
"sync"
"testing"

. "github.com/pingcap/check"
"github.com/stretchr/testify/require"
)

var _ = Suite(&testTiDBSuite{})

type testTiDBSuite struct{}

func TestTableInOrderBuild(t *testing.T) {
tableMap := sync.Map{}
tableInOrder := &tableInOrder{}

tableMap.Store(8, &tableDetail{ID: 8})
tableMap.Store(2, &tableDetail{ID: 2})
tableMap.Store(4, &tableDetail{ID: 4})
tableMap.Store(1, &tableDetail{ID: 1})

tableInOrder.buildFromTableMap(&tableMap)
tableIds := make([]int64, 0, len(tableInOrder.tables))
for _, table := range tableInOrder.tables {
tableIds = append(tableIds, table.ID)
}

require.Equal(t, []int64{1, 2, 4, 8}, tableIds)
}

func TestTableInOrderFindOne(t *testing.T) {
table := &tableInOrder{
tables: []*tableDetail{{ID: 1}, {ID: 2}, {ID: 4}, {ID: 8}},
}
require.Equal(t, table.findOne(1, 2).ID, int64(1))
require.Equal(t, table.findOne(2, 3).ID, int64(2))
require.Equal(t, table.findOne(3, 5).ID, int64(4))
require.Equal(t, table.findOne(8, 18).ID, int64(8))
require.Equal(t, table.findOne(3, 4).ID, int64(4))
require.Nil(t, table.findOne(8, 0))
require.Nil(t, table.findOne(8, 8))
require.Nil(t, table.findOne(80, 81))

table0 := &tableInOrder{
tables: []*tableDetail{},
}
require.Nil(t, table0.findOne(1, 2))

table1 := &tableInOrder{
tables: []*tableDetail{{ID: 2}},
}
require.Equal(t, table1.findOne(1, 2).ID, int64(2))
require.Nil(t, table1.findOne(0, 1))
require.Nil(t, table1.findOne(3, 4))
}
2 changes: 1 addition & 1 deletion scripts/lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ if [ "${NEED_DOWNLOAD}" = true ]; then
fi

echo "+ Run lints for Go source code"
${LINT_BIN} run --fix
${LINT_BIN} run --fix --timeout 3m

echo "+ Clean up go mod"
go mod tidy