nimo-shake/common/shard.go (103 lines of code) (raw):

package utils import ( "fmt" "sort" "strings" "github.com/aws/aws-sdk-go/service/dynamodbstreams" ) var ( StopTraverseSonErr = fmt.Errorf("stop traverse") ) type ShardNode struct { Shard *dynamodbstreams.Shard ShardArn string Sons map[string]*ShardNode Table string } // build shard tree base on the input shard list, return root node func BuildShardTree(shards []*dynamodbstreams.Shard, table string, ShardArn string) *ShardNode { pathMap := make(map[string]*ShardNode, len(shards)) // store the inheritance relationship inDegree := make(map[string]bool, len(shards)) // initial for _, shard := range shards { pathMap[*shard.ShardId] = &ShardNode{ Shard: shard, ShardArn: ShardArn, Sons: make(map[string]*ShardNode), Table: table, } inDegree[*shard.ShardId] = false } // build path for _, shard := range shards { node := pathMap[*shard.ShardId] father := shard.ParentShardId if father != nil { if _, ok := pathMap[*father]; !ok { // father node isn't exist on the pathMap, which means deleted continue } inDegree[*shard.ShardId] = true pathMap[*father].Sons[*shard.ShardId] = node } } // root is fake node rootNode := &ShardNode{ Shard: nil, ShardArn: "", Sons: make(map[string]*ShardNode), Table: table, } for key, val := range inDegree { if val == false { rootNode.Sons[key] = pathMap[key] // fmt.Printf("root->%s\n", key) } } return rootNode } // dfs func TraverseShard(node *ShardNode, callback func(node *ShardNode) error) error { if node == nil { return nil } if node.Shard != nil { // skip root node if err := callback(node); err != nil { if err != StopTraverseSonErr { return err } else { // return if error == StopTraverseSonErr return nil } } // fmt.Printf("%s->%s\n", *node.Shard.ParentShardId, *node.Shard.ShardId) } for _, son := range node.Sons { if err := TraverseShard(son, callback); err != nil { return err } } return nil } // calculate md5. TODO: add UT func CalMd5(root *ShardNode) uint64 { if root == nil { return 0 } list := make([]string, 0, len(root.Sons)) for _, son := range root.Sons { ret := CalMd5(son) list = append(list, fmt.Sprintf("%s->%d", *son.Shard.ShardId, ret)) } sort.Strings(list) concat := strings.Join(list, ";") // fmt.Println("concat: ", concat) return Md5In64(String2Bytes(concat)) } func PrintShardTree(node *ShardNode) (string, error) { newSet := make([]string, 0) err := TraverseShard(node, func(node *ShardNode) error { var father string if node.Shard.ParentShardId != nil { father = *node.Shard.ParentShardId } else { father = "nil" } inheritance := strings.Join([]string{father, *node.Shard.ShardId}, "->") newSet = append(newSet, inheritance) return nil }) if err != nil { return "", err } return strings.Join(newSet, "\n"), nil }