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

tools: balance region simulator #1708

Merged
merged 34 commits into from
Sep 4, 2019
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b9b25dc
add balance region case
lhy1024 Aug 23, 2019
b1d4736
Update task.go
lhy1024 Aug 27, 2019
6c4ae1b
add comment for transfer region counter
lhy1024 Aug 27, 2019
958d4ba
Merge branch 'balance-region-simulator' of github.com:lhy1024/pd into…
lhy1024 Aug 27, 2019
10ac6c2
add unit test for balance region case
lhy1024 Aug 27, 2019
fe41988
add comment and rename var
lhy1024 Aug 27, 2019
bc92d37
update comment
lhy1024 Aug 27, 2019
7090d86
Merge branch 'master' into balance-region-simulator
lhy1024 Aug 27, 2019
5eb2ffc
update license
lhy1024 Aug 27, 2019
2e1987f
format comment
lhy1024 Aug 27, 2019
e4a657e
Update task.go
lhy1024 Aug 27, 2019
4be86b9
clean compaction
lhy1024 Aug 27, 2019
db8d0e8
update task.go
lhy1024 Aug 27, 2019
2c9e415
rename case
lhy1024 Aug 28, 2019
b7fe8ce
remove var `available` and add new param
lhy1024 Aug 28, 2019
c041f76
add config for flag
lhy1024 Aug 28, 2019
b22714a
fix cycle import and add config for flags
lhy1024 Aug 28, 2019
8e3b933
rename flags and format log
lhy1024 Aug 29, 2019
3698f19
add judge for avoiding to influence other case
lhy1024 Aug 29, 2019
68f3f8b
remove default config for all cases
lhy1024 Aug 29, 2019
9d88133
fix panic when delete_nodes.go
lhy1024 Aug 29, 2019
8a39ad3
rename case and format log
lhy1024 Aug 29, 2019
2891f23
split transfer region count
lhy1024 Aug 30, 2019
767586e
Merge branch 'master' into balance-region-simulator
lhy1024 Aug 30, 2019
3a9925a
rename package
lhy1024 Aug 30, 2019
133ad02
add support for sparse stores
lhy1024 Sep 2, 2019
bcc33c6
format redundant balance region log
lhy1024 Sep 3, 2019
a136941
add solve for file error
lhy1024 Sep 3, 2019
e815f66
format comment and rename package
lhy1024 Sep 3, 2019
35d966c
Merge branch 'master' into balance-region-simulator
lhy1024 Sep 3, 2019
a969796
rename package
lhy1024 Sep 4, 2019
6b26e47
Merge branch 'balance-region-simulator' of github.com:lhy1024/pd into…
lhy1024 Sep 4, 2019
7f24cef
add isReady
lhy1024 Sep 4, 2019
a1b9336
use singleton
lhy1024 Sep 4, 2019
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
178 changes: 178 additions & 0 deletions tools/pd-analysis/transfer_region_counter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright 2019 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package pdAnalysis

import (
"fmt"
"os"
"strconv"
"strings"
"sync"
)

// TransferRegionCount is to count transfer schedule for judging whether redundant
type TransferRegionCount struct {
storeNum int
regionNum int
IsValid bool
Redundant uint64
Necessary uint64
regionMap map[uint64]uint64
visited []bool
GraphMat [][]uint64
mutex sync.Mutex
loopResultPath [][]int
loopResultCount []uint64
}

// TransferRegionCounter is an global instance for TransferRegionCount
var TransferRegionCounter TransferRegionCount

// Init for TransferRegionCount
func (c *TransferRegionCount) Init(storeNum, regionNum int) {
c.storeNum = storeNum
c.regionNum = regionNum
c.IsValid = true
c.Redundant = 0
c.Necessary = 0
c.regionMap = make(map[uint64]uint64)
c.visited = make([]bool, c.storeNum+1)
for i := 0; i < c.storeNum+1; i++ {
tmp := make([]uint64, c.storeNum+1)
c.GraphMat = append(c.GraphMat, tmp)
}
c.loopResultPath = c.loopResultPath[:0]
c.loopResultCount = c.loopResultCount[:0]
}

// AddTarget is be used to add target of edge in graph mat.
// Firstly add a new peer and then delete the old peer of the scheduling,
// So in the statistics, also firstly add the target and then add the source.
func (c *TransferRegionCount) AddTarget(regionID, targetStoreID uint64) {
c.mutex.Lock()
defer c.mutex.Unlock()
c.regionMap[regionID] = targetStoreID
}

// AddSource is be used to add source of edge in graph mat.
func (c *TransferRegionCount) AddSource(regionID, sourceStoreID uint64) {
c.mutex.Lock()
defer c.mutex.Unlock()
if targetStoreID, ok := c.regionMap[regionID]; ok {
c.GraphMat[sourceStoreID][targetStoreID]++
delete(c.regionMap, regionID)
} else {
fmt.Println("Error when add sourceStoreID %u with regionID %u in transfer region map", sourceStoreID, regionID)
os.Exit(-1)
}
}

//DFS is used to find all the looped flow in such a directed graph.
//For each point U in the graph, a DFS is performed, and push the passing point v
//to the stack. If there is an edge of `v->u`, then the corresponding looped flow
//is marked and removed. When all the output edges of the point v are traversed,
//pop the point v out of the stack.
func (c *TransferRegionCount) DFS(cur int, curFlow uint64, path []int) {
//push stack
path = append(path, cur)
c.visited[cur] = true

for target := path[0]; target < c.storeNum+1; target++ {
flow := c.GraphMat[cur][target]
if flow == 0 {
continue
}
if path[0] == target { //is a loop
//get curMinFlow
curMinFlow := flow
for i := 0; i < len(path)-1; i++ {
pathFlow := c.GraphMat[path[i]][path[i+1]]
if curMinFlow > pathFlow {
curMinFlow = pathFlow
}
}
//set curMinFlow
if curMinFlow != 0 {
c.loopResultPath = append(c.loopResultPath, path)
c.loopResultCount = append(c.loopResultCount, curMinFlow*uint64(len(path)))
for i := 0; i < len(path)-1; i++ {
c.GraphMat[path[i]][path[i+1]] -= curMinFlow
}
c.GraphMat[cur][target] -= curMinFlow
}
} else if !c.visited[target] {
c.DFS(target, flow, path)
}
}
//pop stack
c.visited[cur] = false
}

//Result will count redundant schedule and necessary schedule
func (c *TransferRegionCount) Result() {
for i := 0; i < c.storeNum; i++ {
c.DFS(i+1, 1<<16, make([]int, 0))
}

for _, value := range c.loopResultCount {
c.Redundant += value
}

for _, row := range c.GraphMat {
for _, flow := range row {
c.Necessary += flow
}
}
}

// PrintGraph will print current graph mat.
func (c *TransferRegionCount) PrintGraph() {
for _, value := range c.GraphMat {
fmt.Println(value)
}
}

// PrintResult will print result to log and csv file.
func (c *TransferRegionCount) PrintResult() {
//Output log
fmt.Println("Total Schedules Graph: ")
c.PrintGraph()
//Solve data
c.Result()
//Output log
fmt.Println("Redundant Loop: ")
for index, value := range c.loopResultPath {
fmt.Println(index, value, c.loopResultCount[index])
}
fmt.Println("Necessary Schedules Graph: ")
c.PrintGraph()
fmt.Println("Redundant Schedules: ", c.Redundant)
fmt.Println("Necessary Schedules: ", c.Necessary)

//Output csv file
fd, _ := os.OpenFile("result.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
fdContent := strings.Join([]string{
toString(uint64(c.storeNum)),
toString(uint64(c.regionNum)),
toString(c.Redundant),
toString(c.Necessary),
}, ",") + "\n"
buf := []byte(fdContent)
_, _ = fd.Write(buf)
_ = fd.Close()
}

func toString(num uint64) string {
return strconv.FormatInt(int64(num), 10)
}
92 changes: 92 additions & 0 deletions tools/pd-analysis/transfer_region_counter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2019 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package pdAnalysis

import (
. "github.com/pingcap/check"
"testing"
)

func TestCounter(t *testing.T) {
TestingT(t)
}

var _ = Suite(&testCounterRedundantSuite{})

type testCounterRedundantSuite struct{}

func (t *testCounterRedundantSuite) TestCounterRedundant(c *C) {
{
test := [][]uint64{
{0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 4, 0, 0},
{0, 0, 0, 0, 8, 9, 6},
{0, 0, 1, 0, 0, 3, 2},
{0, 2, 3, 4, 0, 3, 0},
{0, 5, 9, 0, 0, 0, 0},
{0, 0, 8, 0, 0, 0, 0}}
TransferRegionCounter.Init(6, 3000)
c.Assert(TransferRegionCounter.Redundant, Equals, uint64(0))
c.Assert(TransferRegionCounter.Necessary, Equals, uint64(0))
TransferRegionCounter.GraphMat = test
TransferRegionCounter.Result()
c.Assert(TransferRegionCounter.Redundant, Equals, uint64(64))
c.Assert(TransferRegionCounter.Necessary, Equals, uint64(5))
}
{
test := [][]uint64{
{0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 2, 0},
{0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0, 0}}
TransferRegionCounter.Init(6, 3000)
c.Assert(TransferRegionCounter.Redundant, Equals, uint64(0))
c.Assert(TransferRegionCounter.Necessary, Equals, uint64(0))
TransferRegionCounter.GraphMat = test
TransferRegionCounter.Result()
c.Assert(TransferRegionCounter.Redundant, Equals, uint64(0))
c.Assert(TransferRegionCounter.Necessary, Equals, uint64(5))
}
{
test := [][]uint64{
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 15, 42, 21, 84, 9, 38, 5},
{0, 76, 0, 84, 3, 130, 0, 129, 0},
{0, 0, 35, 0, 86, 0, 60, 0, 15},
{0, 143, 0, 106, 0, 178, 0, 132, 0},
{0, 0, 101, 0, 120, 0, 118, 1, 33},
{0, 133, 0, 140, 0, 93, 0, 114, 0},
{0, 0, 48, 0, 84, 1, 48, 0, 20},
{0, 61, 2, 57, 7, 122, 1, 21, 0}}
TransferRegionCounter.Init(8, 3000)
c.Assert(TransferRegionCounter.Redundant, Equals, uint64(0))
c.Assert(TransferRegionCounter.Necessary, Equals, uint64(0))
TransferRegionCounter.GraphMat = test
TransferRegionCounter.Result()
c.Assert(TransferRegionCounter.Redundant, Equals, uint64(1778))
c.Assert(TransferRegionCounter.Necessary, Equals, uint64(938))
}
}

func (t *testCounterRedundantSuite) TestAddEdge(c *C) {
{
TransferRegionCounter.Init(6, 3000)
TransferRegionCounter.AddTarget(130, 3)
TransferRegionCounter.AddSource(130, 2)
c.Assert(TransferRegionCounter.GraphMat[2][3], Equals, uint64(1))
}
}
21 changes: 16 additions & 5 deletions tools/pd-simulator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/pingcap/pd/server/api"
"github.com/pingcap/pd/server/config"
"github.com/pingcap/pd/server/statistics"
"github.com/pingcap/pd/tools/pd-analysis"
"github.com/pingcap/pd/tools/pd-simulator/simulator"
"github.com/pingcap/pd/tools/pd-simulator/simulator/cases"
"github.com/pingcap/pd/tools/pd-simulator/simulator/simutil"
Expand All @@ -41,18 +42,25 @@ import (
)

var (
pdAddr = flag.String("pd", "", "pd address")
configFile = flag.String("config", "conf/simconfig.toml", "config file")
caseName = flag.String("case", "", "case name")
serverLogLevel = flag.String("serverLog", "fatal", "pd server log level.")
simLogLevel = flag.String("simLog", "fatal", "simulator log level.")
pdAddr = flag.String("pd", "", "pd address")
configFile = flag.String("config", "conf/simconfig.toml", "config file")
caseName = flag.String("case", "", "case name")
serverLogLevel = flag.String("serverLog", "fatal", "pd server log level.")
simLogLevel = flag.String("simLog", "fatal", "simulator log level.")
regionNum = flag.Int("regionNum", 0, "regionNum of one store")
storeNum = flag.Int("storeNum", 0, "storeNum")
enableTransferRegionCounter = flag.Bool("enableTransferRegionCounter", false, "enableTransferRegionCounter")
)

func main() {
flag.Parse()

simutil.InitLogger(*simLogLevel)
simutil.InitCaseConfig(*storeNum, *regionNum, *enableTransferRegionCounter)
statistics.Denoising = false
if simutil.CaseConfigure.EnableTransferRegionCounter {
pdAnalysis.TransferRegionCounter.Init(simutil.CaseConfigure.StoreNum, simutil.CaseConfigure.RegionNum)
}

if *caseName == "" {
if *pdAddr != "" {
Expand Down Expand Up @@ -172,6 +180,9 @@ EXIT:

fmt.Printf("%s [%s] total iteration: %d, time cost: %v\n", simResult, simCase, driver.TickCount(), time.Since(start))
driver.PrintStatistics()
if pdAnalysis.TransferRegionCounter.IsValid {
pdAnalysis.TransferRegionCounter.PrintResult()
}

if simResult != "OK" {
os.Exit(1)
Expand Down
3 changes: 2 additions & 1 deletion tools/pd-simulator/simulator/cases/add_nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package cases
import (
"github.com/pingcap/kvproto/pkg/metapb"
"github.com/pingcap/pd/server/core"
"github.com/pingcap/pd/tools/pd-simulator/simulator/dto"
"github.com/pingcap/pd/tools/pd-simulator/simulator/simutil"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -47,7 +48,7 @@ func newAddNodes() *Case {
})
}

simCase.Checker = func(regions *core.RegionsInfo) bool {
simCase.Checker = func(regions *core.RegionsInfo, stats []dto.StoreStats) bool {
res := true
leaderCounts := make([]int, 0, 8)
regionCounts := make([]int, 0, 8)
Expand Down
3 changes: 2 additions & 1 deletion tools/pd-simulator/simulator/cases/add_nodes_dynamic.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package cases
import (
"github.com/pingcap/kvproto/pkg/metapb"
"github.com/pingcap/pd/server/core"
"github.com/pingcap/pd/tools/pd-simulator/simulator/dto"
"github.com/pingcap/pd/tools/pd-simulator/simulator/simutil"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -65,7 +66,7 @@ func newAddNodesDynamic() *Case {
}
simCase.Events = []EventDescriptor{e}

simCase.Checker = func(regions *core.RegionsInfo) bool {
simCase.Checker = func(regions *core.RegionsInfo, stats []dto.StoreStats) bool {
res := true
leaderCounts := make([]int, 0, numNodes)
regionCounts := make([]int, 0, numNodes)
Expand Down
3 changes: 2 additions & 1 deletion tools/pd-simulator/simulator/cases/balance_leader.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package cases
import (
"github.com/pingcap/kvproto/pkg/metapb"
"github.com/pingcap/pd/server/core"
"github.com/pingcap/pd/tools/pd-simulator/simulator/dto"
"github.com/pingcap/pd/tools/pd-simulator/simulator/simutil"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -48,7 +49,7 @@ func newBalanceLeader() *Case {
})
}

simCase.Checker = func(regions *core.RegionsInfo) bool {
simCase.Checker = func(regions *core.RegionsInfo, stats []dto.StoreStats) bool {
count1 := regions.GetStoreLeaderCount(1)
count2 := regions.GetStoreLeaderCount(2)
count3 := regions.GetStoreLeaderCount(3)
Expand Down
Loading