Skip to content

Commit 54e18df

Browse files
authored
*: refactor error system (pingcap#216)
1 parent 612c2dc commit 54e18df

File tree

127 files changed

+3674
-1547
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+3674
-1547
lines changed

Makefile

+5-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ unit_test:
6666
|| { $(FAILPOINT_DISABLE); exit 1; }
6767
$(FAILPOINT_DISABLE)
6868

69-
check: fmt lint vet
69+
check: fmt lint vet terror_check
7070

7171
fmt:
7272
@echo "gofmt (simplify)"
@@ -88,6 +88,10 @@ vet:
8888
@$(GO) vet -composites=false $(PACKAGES)
8989
@$(GO) vet -vettool=$(CURDIR)/bin/shadow $(PACKAGES) || true
9090

91+
terror_check:
92+
@echo "check terror conflict"
93+
_utils/terror_gen/check.sh
94+
9195
dm_integration_test_build:
9296
which $(FAILPOINT) >/dev/null 2>&1 || $(GOBUILD) -o $(FAILPOINT) github.com/pingcap/failpoint/failpoint-ctl
9397
$(FAILPOINT_ENABLE)

_utils/terror_gen/README.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Terror check tool
2+
3+
## Principle
4+
5+
* gen.go: read and parse the ast of error_list file to generate current error information, and generate checker_generated.go
6+
* checker_template.go: code template for checker
7+
* checker_generated.go: check whether current errors have conflict with the previous version, checklist as follows:
8+
- check each error that is not newly added in develop version has the same error code with the release version
9+
- check each error in develop version has a unique error code
10+
* errors_release.txt: generated error information list
11+
12+
## Run
13+
14+
Run `check.sh` will automatically check the valid of error list, if no conflict is detected, errors_release.txt will be updated with latest error list. Each time we change errors definition in error_list, we must run `make terror_check`, which will call `check.sh` directly.

_utils/terror_gen/check.sh

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/bash
2+
3+
set -eu
4+
5+
CUR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
6+
7+
PWD=$(pwd)
8+
9+
trap "cd $PWD" EXIT
10+
cd $CUR
11+
GO111MODULE=on go build gen.go && ./gen ../../pkg/terror/error_list.go && rm gen
12+
GO111MODULE=on go run checker_generated.go
13+
git diff --quiet -- errors_release.txt

_utils/terror_gen/checker_template.go

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// Copyright 2019 PingCAP, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package main
15+
16+
import (
17+
"bufio"
18+
"fmt"
19+
"os"
20+
"regexp"
21+
"strconv"
22+
"strings"
23+
24+
"github.com/pingcap/dm/pkg/terror"
25+
)
26+
27+
const (
28+
developErrorFile = "errors_develop.txt"
29+
releaseErrorFile = "errors_release.txt"
30+
generatedCheckerFile = "{{.CheckerFile}}"
31+
)
32+
33+
var dumpErrorRe = regexp.MustCompile("^([a-zA-Z].*),\\[code=([0-9]+).*$")
34+
35+
var errors = []struct {
36+
name string
37+
err *terror.Error
38+
}{
39+
// sample:
40+
// {"ErrWorkerExecDDLTimeout", terror.ErrWorkerExecDDLTimeout},
41+
// {{.ErrList}}
42+
}
43+
44+
func genErrors() {
45+
f, err := os.Create(developErrorFile)
46+
if err != nil {
47+
panic(err)
48+
}
49+
defer f.Close()
50+
w := bufio.NewWriter(f)
51+
for _, item := range errors {
52+
s := strings.SplitN(item.err.Error(), " ", 2)
53+
w.WriteString(fmt.Sprintf("%s,%s,\"%s\"\n", item.name, s[0], strings.ReplaceAll(s[1], "\n", "\\n")))
54+
}
55+
w.Flush()
56+
}
57+
58+
func readErrorFile(filename string) map[string]int64 {
59+
f, err := os.Open(filename)
60+
if err != nil {
61+
panic(err)
62+
}
63+
defer f.Close()
64+
65+
result := make(map[string]int64)
66+
scanner := bufio.NewScanner(f)
67+
for scanner.Scan() {
68+
s := scanner.Text()
69+
match := dumpErrorRe.FindStringSubmatch(s)
70+
if len(match) != 3 {
71+
panic(fmt.Sprintf("invalid error: %s", s))
72+
}
73+
code, err := strconv.ParseInt(match[2], 10, 64)
74+
if err != nil {
75+
panic(err)
76+
}
77+
result[match[1]] = code
78+
}
79+
return result
80+
}
81+
82+
func compareErrors() bool {
83+
changedErrorCode := make(map[string][]int64)
84+
duplicateErrorCode := make(map[int64][]string)
85+
release := readErrorFile(releaseErrorFile)
86+
dev := readErrorFile(developErrorFile)
87+
88+
for name, code := range dev {
89+
if releaseCode, ok := release[name]; ok && code != releaseCode {
90+
changedErrorCode[name] = []int64{releaseCode, code}
91+
}
92+
if _, ok := duplicateErrorCode[code]; ok {
93+
duplicateErrorCode[code] = append(duplicateErrorCode[code], name)
94+
} else {
95+
duplicateErrorCode[code] = []string{name}
96+
}
97+
}
98+
for code, names := range duplicateErrorCode {
99+
if len(names) == 1 {
100+
delete(duplicateErrorCode, code)
101+
}
102+
}
103+
104+
// check each non-new-added error in develop version has the same error code with the release version
105+
if len(changedErrorCode) > 0 {
106+
os.Stderr.WriteString("\n************ error code not same with the release version ************\n")
107+
}
108+
for name, codes := range changedErrorCode {
109+
fmt.Fprintf(os.Stderr, "name: %s release code: %d current code: %d\n", name, codes[0], codes[1])
110+
}
111+
112+
// check each error in develop version has a unique error code
113+
if len(duplicateErrorCode) > 0 {
114+
os.Stderr.WriteString("\n************ error code not unique ************\n")
115+
}
116+
for code, names := range duplicateErrorCode {
117+
fmt.Fprintf(os.Stderr, "code: %d names: %v\n", code, names)
118+
}
119+
120+
return len(changedErrorCode) == 0 && len(duplicateErrorCode) == 0
121+
}
122+
123+
func cleanup(success bool) {
124+
if success {
125+
if err := os.Rename(developErrorFile, releaseErrorFile); err != nil {
126+
panic(err)
127+
}
128+
fmt.Println("check pass")
129+
} else {
130+
if err := os.Remove(developErrorFile); err != nil {
131+
panic(err)
132+
}
133+
os.Exit(1)
134+
}
135+
}
136+
137+
func main() {
138+
defer func() {
139+
os.Remove(generatedCheckerFile)
140+
}()
141+
genErrors()
142+
cleanup(compareErrors())
143+
}

0 commit comments

Comments
 (0)