@@ -21,7 +21,6 @@ import (
21
21
"io"
22
22
"os"
23
23
"path/filepath"
24
- "regexp"
25
24
"runtime"
26
25
"sort"
27
26
"strconv"
@@ -47,6 +46,7 @@ import (
47
46
"github.com/pingcap/tidb/util/execdetails"
48
47
"github.com/pingcap/tidb/util/hack"
49
48
"github.com/pingcap/tidb/util/logutil"
49
+ "github.com/pingcap/tidb/util/mathutil"
50
50
"github.com/pingcap/tidb/util/memory"
51
51
"github.com/pingcap/tidb/util/plancodec"
52
52
"go.uber.org/zap"
@@ -526,32 +526,99 @@ func getLineIndex(offset offset, index int) int {
526
526
return fileLine
527
527
}
528
528
529
- // kvSplitRegex: it was just for split "field: value field: value..."
530
- var kvSplitRegex = regexp .MustCompile (`\w+: ` )
529
+ // findMatchedRightBracket returns the rightBracket index which matchs line[leftBracketIdx]
530
+ // leftBracketIdx should be valid string index for line
531
+ // Returns -1 if invalid inputs are given
532
+ func findMatchedRightBracket (line string , leftBracketIdx int ) int {
533
+ leftBracket := line [leftBracketIdx ]
534
+ rightBracket := byte ('}' )
535
+ if leftBracket == '[' {
536
+ rightBracket = ']'
537
+ } else if leftBracket != '{' {
538
+ return - 1
539
+ }
540
+ lineLength := len (line )
541
+ current := leftBracketIdx
542
+ leftBracketCnt := 0
543
+ for current < lineLength {
544
+ b := line [current ]
545
+ if b == leftBracket {
546
+ leftBracketCnt ++
547
+ current ++
548
+ } else if b == rightBracket {
549
+ leftBracketCnt --
550
+ if leftBracketCnt > 0 {
551
+ current ++
552
+ } else if leftBracketCnt == 0 {
553
+ if current + 1 < lineLength && line [current + 1 ] != ' ' {
554
+ return - 1
555
+ }
556
+ return current
557
+ } else {
558
+ return - 1
559
+ }
560
+ } else {
561
+ current ++
562
+ }
563
+ }
564
+ return - 1
565
+ }
566
+
567
+ func isLetterOrNumeric (b byte ) bool {
568
+ return ('A' <= b && b <= 'Z' ) || ('a' <= b && b <= 'z' ) || ('0' <= b && b <= '9' )
569
+ }
531
570
532
571
// splitByColon split a line like "field: value field: value..."
572
+ // Note:
573
+ // 1. field string's first character can only be ASCII letters or digits, and can't contain ':'
574
+ // 2. value string may be surrounded by brackets, allowed brackets includes "[]" and "{}", like {key: value,{key: value}}
575
+ // "[]" can only be nested inside "[]"; "{}" can only be nested inside "{}"
576
+ // 3. value string can't contain ' ' character unless it is inside brackets
533
577
func splitByColon (line string ) (fields []string , values []string ) {
534
- matches := kvSplitRegex .FindAllStringIndex (line , - 1 )
535
- fields = make ([]string , 0 , len (matches ))
536
- values = make ([]string , 0 , len (matches ))
537
-
538
- beg := 0
539
- end := 0
540
- for _ , match := range matches {
541
- // trim ": "
542
- fields = append (fields , line [match [0 ]:match [1 ]- 2 ])
543
-
544
- end = match [0 ]
545
- if beg != 0 {
546
- // trim " "
547
- values = append (values , line [beg :end - 1 ])
548
- }
549
- beg = match [1 ]
578
+ fields = make ([]string , 0 , 1 )
579
+ values = make ([]string , 0 , 1 )
580
+
581
+ lineLength := len (line )
582
+ parseKey := true
583
+ start := 0
584
+ errMsg := ""
585
+ for current := 0 ; current < lineLength ; {
586
+ if parseKey {
587
+ // Find key start
588
+ for current < lineLength && ! isLetterOrNumeric (line [current ]) {
589
+ current ++
590
+ }
591
+ start = current
592
+ if current >= lineLength {
593
+ break
594
+ }
595
+ for current < lineLength && line [current ] != ':' {
596
+ current ++
597
+ }
598
+ fields = append (fields , line [start :current ])
599
+ parseKey = false
600
+ current += 2 // bypass ": "
601
+ } else {
602
+ start = current
603
+ if current < lineLength && (line [current ] == '{' || line [current ] == '[' ) {
604
+ rBraceIdx := findMatchedRightBracket (line , current )
605
+ if rBraceIdx == - 1 {
606
+ errMsg = "Braces matched error"
607
+ break
608
+ }
609
+ current = rBraceIdx + 1
610
+ } else {
611
+ for current < lineLength && line [current ] != ' ' {
612
+ current ++
613
+ }
614
+ }
615
+ values = append (values , line [start :mathutil .Min (current , len (line ))])
616
+ parseKey = true
617
+ }
550
618
}
551
-
552
- if end != len (line ) {
553
- // " " does not exist in the end
554
- values = append (values , line [beg :])
619
+ if len (errMsg ) > 0 {
620
+ logutil .BgLogger ().Warn ("slow query parse slow log error" , zap .String ("Error" , errMsg ), zap .String ("Log" , line ))
621
+ return nil , nil
555
622
}
556
623
return fields , values
557
624
}
0 commit comments