Skip to content

Commit db5e6bf

Browse files
committedNov 22, 2024··
Move schema info definition from flag to parameters, add FileType to schema info and deduce that type from the json input itself
Signed-off-by: Rohit Nayak <rohit@planetscale.com>
1 parent a39acc3 commit db5e6bf

File tree

5 files changed

+145
-7
lines changed

5 files changed

+145
-7
lines changed
 

‎go/cmd/summarize.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424

2525
func summarizeCmd() *cobra.Command {
2626
var hotMetric string
27-
var schemaInfoPath string
2827

2928
cmd := &cobra.Command{
3029
Use: "summarize old_file.json [new_file.json]",
@@ -33,12 +32,11 @@ func summarizeCmd() *cobra.Command {
3332
Example: "vt summarize old.json new.json",
3433
Args: cobra.RangeArgs(1, 2),
3534
Run: func(_ *cobra.Command, args []string) {
36-
summarize.Run(args, hotMetric, schemaInfoPath)
35+
summarize.Run(args, hotMetric)
3736
},
3837
}
3938

4039
cmd.Flags().StringVar(&hotMetric, "hot-metric", "total-time", "Metric to determine hot queries (options: usage-count, total-rows-examined, avg-rows-examined, avg-time, total-time)")
41-
cmd.Flags().StringVar(&schemaInfoPath, "schema-info-path", "", "Path to output of 'vt schema' command (optional)")
4240

4341
return cmd
4442
}

‎go/summarize/summarize.go

+19-4
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,25 @@ type (
3939
}
4040
)
4141

42-
func Run(files []string, hotMetric, schemaInfoPath string) {
43-
traces := make([]readingSummary, len(files))
42+
func Run(files []string, hotMetric string) {
43+
var traceFiles []string
44+
var dbInfoPath string
45+
// todo: add file types for other json types. Right now just checks for dbinfo files, else defaults
46+
for _, file := range files {
47+
typ, _ := getFileType(file)
48+
switch typ {
49+
case dbInfoFile:
50+
fmt.Printf("dbinfo file: %s\n", file)
51+
dbInfoPath = file
52+
default:
53+
fmt.Printf("trace file: %s\n", file)
54+
traceFiles = append(traceFiles, file)
55+
}
56+
}
57+
58+
traces := make([]readingSummary, len(traceFiles))
4459
var err error
45-
for i, arg := range files {
60+
for i, arg := range traceFiles {
4661
traces[i], err = readTraceFile(arg)
4762
if err != nil {
4863
exit(err.Error())
@@ -62,7 +77,7 @@ func Run(files []string, hotMetric, schemaInfoPath string) {
6277
if firstTrace.AnalysedQueries == nil {
6378
printTraceSummary(os.Stdout, terminalWidth(), highlightQuery, firstTrace)
6479
} else {
65-
printKeysSummary(os.Stdout, firstTrace, time.Now(), hotMetric, schemaInfoPath)
80+
printKeysSummary(os.Stdout, firstTrace, time.Now(), hotMetric, dbInfoPath)
6681
}
6782
}
6883

‎go/summarize/utils.go

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package summarize
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"os"
8+
)
9+
10+
type fileType int
11+
12+
const (
13+
unknownFile fileType = iota
14+
traceFile
15+
keysFile
16+
dbInfoFile
17+
)
18+
19+
var fileTypeMap = map[string]fileType{
20+
"trace": traceFile,
21+
"keys": keysFile,
22+
"dbinfo": dbInfoFile,
23+
}
24+
25+
// getFileType reads the first key-value pair from a JSON file and returns the type of the file
26+
// Note:
27+
func getFileType(filename string) (fileType, error) {
28+
// read json file
29+
file, err := os.Open(filename)
30+
if err != nil {
31+
return unknownFile, errors.New(fmt.Sprintf("error opening file: %v", err))
32+
}
33+
defer file.Close()
34+
35+
decoder := json.NewDecoder(file)
36+
37+
token, err := decoder.Token()
38+
if err != nil {
39+
return unknownFile, errors.New(fmt.Sprintf("Error reading token: %v", err))
40+
}
41+
42+
// Ensure the token is the start of an object
43+
if delim, ok := token.(json.Delim); !ok || delim != '{' {
44+
return unknownFile, errors.New(fmt.Sprintf("Expected start of object '{'"))
45+
}
46+
47+
// Read the key-value pairs
48+
for decoder.More() {
49+
// Read the key
50+
keyToken, err := decoder.Token()
51+
if err != nil {
52+
return unknownFile, errors.New(fmt.Sprintf("Error reading key token: %v", err))
53+
}
54+
55+
key, ok := keyToken.(string)
56+
if !ok {
57+
return unknownFile, errors.New(fmt.Sprintf("Expected key to be a string: %s", keyToken))
58+
}
59+
60+
// Read the value
61+
valueToken, err := decoder.Token()
62+
if err != nil {
63+
return unknownFile, errors.New(fmt.Sprintf("Error reading value token: %v", err))
64+
}
65+
66+
// Check if the key is "FileType"
67+
if key == "FileType" {
68+
if fileType, ok := fileTypeMap[valueToken.(string)]; ok {
69+
return fileType, nil
70+
} else {
71+
return unknownFile, errors.New(fmt.Sprintf("Unknown FileType: %s", valueToken))
72+
}
73+
} else {
74+
// Currently we expect the first key to be FileType, for optimization reasons
75+
return unknownFile, nil
76+
}
77+
}
78+
return unknownFile, nil
79+
}

‎go/summarize/utils_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package summarize
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
// Test utils getFileType function
10+
func TestGetFileType(t *testing.T) {
11+
type testCase struct {
12+
filename string
13+
expectedType fileType
14+
expectedError string
15+
}
16+
testCases := []testCase{
17+
{
18+
filename: "../testdata/keys-log.json",
19+
expectedType: unknownFile,
20+
},
21+
{
22+
filename: "../testdata/sakila-schema-info.json",
23+
expectedType: dbInfoFile,
24+
},
25+
{
26+
filename: "../testdata/mysql.query.log",
27+
expectedType: unknownFile,
28+
expectedError: "Error reading token",
29+
},
30+
}
31+
for _, tc := range testCases {
32+
t.Run(tc.filename, func(t *testing.T) {
33+
ft, err := getFileType(tc.filename)
34+
if tc.expectedError != "" {
35+
require.Error(t, err)
36+
}
37+
if err != nil {
38+
require.Contains(t, err.Error(), tc.expectedError)
39+
}
40+
if ft != tc.expectedType {
41+
t.Errorf("Expected type: %v, got: %v", tc.expectedType, ft)
42+
}
43+
})
44+
}
45+
}

‎go/testdata/sakila-schema-info.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"FileType": "dbinfo",
23
"Tables": [
34
{
45
"Name": "actor",

0 commit comments

Comments
 (0)
Please sign in to comment.