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