Skip to content

Commit 48af694

Browse files
authored
Merge pull request pingcap#4 from ti2sky/add-replay
add init
2 parents b9159cf + 9848a0e commit 48af694

File tree

9 files changed

+139
-115
lines changed

9 files changed

+139
-115
lines changed

replay_file

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
5 3 test begin
2+
3 4 test begin
3+
5 5 test insert into t values(5)
4+
3 6 test insert into t values(6)
5+
5 7 test commit
6+
5 8 test select * from t
7+
3 8 test commit
8+
5 8 test commit

server/conn.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,6 @@ func (cc *clientConn) Run(ctx context.Context) {
10301030
terror.Log(err)
10311031
}
10321032
}()
1033-
10341033
// Usually, client connection status changes between [dispatching] <=> [reading].
10351034
// When some event happens, server may notify this client connection by setting
10361035
// the status to special values, for example: kill or graceful shutdown.

server/http_status.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,8 @@ func (s *Server) startHTTPServer() {
258258
router.Handle("/metrics/profile", profileHandler{tikvHandlerTool})
259259
fmt.Println("register replay sql")
260260
// HTTP path for start record and replay sql.
261-
router.Handle("/record/{filename}/{status}/{startTS}", s.newSQLRecorderHandler())
262-
router.Handle("/replay/{filename}", s.newSQLRecorderHandler())
261+
router.Handle("/record/{filename}/{recordStatus}/{startTS}", s.newSQLRecorderHandler())
262+
router.Handle("/replay/{filename}/{replayStatus}", s.newSQLReplayHandler(tikvHandlerTool.Store))
263263
// HTTP path for web UI.
264264
if host, port, err := net.SplitHostPort(s.statusAddr); err == nil {
265265
if host == "" {

server/sql_replayer.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ package server
1616

1717
import (
1818
"fmt"
19+
"github.com/pingcap/tidb/util/replayutil"
1920
"net/http"
2021
"strconv"
2122

22-
"github.com/pingcap/tidb/util/logutil"
23-
2423
"github.com/gorilla/mux"
2524
"github.com/pingcap/tidb/config"
25+
"github.com/pingcap/tidb/kv"
26+
"github.com/pingcap/tidb/util/logutil"
2627
)
2728

2829
// SQLRecorderHandler is the handler for dumping plan replayer file.
@@ -45,6 +46,7 @@ func (h SQLRecorderHandler) ServeHTTP(w http.ResponseWriter, req *http.Request)
4546
cfg := config.GetGlobalConfig()
4647
params := mux.Vars(req)
4748
if status, ok := params[pRecordStatus]; ok {
49+
fmt.Println()
4850
if status == "on" {
4951
// set replay meta TS first.
5052
cfg.ReplayMetaTS, err = strconv.ParseInt(params[pStartTS], 10, 64)
@@ -61,29 +63,31 @@ func (h SQLRecorderHandler) ServeHTTP(w http.ResponseWriter, req *http.Request)
6163
}
6264
w.WriteHeader(http.StatusOK)
6365
return
64-
} else {
65-
w.WriteHeader(http.StatusBadRequest)
6666
}
67+
w.WriteHeader(http.StatusBadRequest)
68+
6769
}
6870

69-
type SQLReplayHandler struct{}
71+
// SQLReplayHandler Replay handler
72+
type SQLReplayHandler struct {
73+
Store kv.Storage
74+
}
7075

71-
func (s *Server) newSQLReplayHandler() *SQLReplayHandler {
72-
prh := &SQLReplayHandler{}
76+
func (s *Server) newSQLReplayHandler(store kv.Storage) *SQLReplayHandler {
77+
prh := &SQLReplayHandler{store}
7378
return prh
7479
}
7580

7681
func (h SQLReplayHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
7782
params := mux.Vars(req)
7883
if status, ok := params[pReplayStatus]; ok {
7984
if status == "on" {
80-
logutil.StartReplay(params[pFileName])
85+
replayutil.StartReplay(params[pFileName], h.Store)
8186
} else {
82-
logutil.StopReplay()
87+
replayutil.StopReplay()
8388
}
8489
w.WriteHeader(http.StatusOK)
8590
return
86-
} else {
87-
w.WriteHeader(http.StatusBadRequest)
8891
}
92+
w.WriteHeader(http.StatusBadRequest)
8993
}

session/session.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2866,12 +2866,12 @@ func logGeneralQuery(execStmt *executor.ExecStmt, s *session, isPrepared bool) {
28662866
cfg := config.GetGlobalConfig()
28672867
vars := s.GetSessionVars()
28682868
if !s.isInternal() && cfg.EnableReplaySQL.Load() {
2869-
go func(sql, id string, intxn bool) {
2869+
fmt.Println("print sql")
2870+
go func(sql, id string) {
2871+
//TODO: We need to add a client col also.
28702872
var builder strings.Builder
2871-
if intxn {
2872-
builder.WriteString(id)
2873-
builder.WriteString(" ")
2874-
}
2873+
builder.WriteString(fmt.Sprintf("%v", vars.ConnectionID))
2874+
builder.WriteString(" ")
28752875
// Logic TS
28762876
ts := strconv.FormatInt(s.sessionVars.StartTime.Unix()-cfg.ReplayMetaTS, 10)
28772877
builder.WriteString(ts)
@@ -2880,7 +2880,7 @@ func logGeneralQuery(execStmt *executor.ExecStmt, s *session, isPrepared bool) {
28802880
builder.WriteString(text)
28812881
builder.WriteString("\n")
28822882
logutil.PutRecordOrDrop(builder.String())
2883-
}(vars.SQL, vars.TxnCtx.ID.String(), vars.InTxn())
2883+
}(vars.SQL, vars.TxnCtx.ID.String())
28842884
}
28852885

28862886
if variable.ProcessGeneralLog.Load() && !vars.InRestrictedSQL {

session/session_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"strings"
2828
"sync"
2929
"sync/atomic"
30+
"testing"
3031
"time"
3132

3233
"github.com/docker/go-units"

util/logutil/record_logger.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func StopRecord() {
2222
RecordLogger.stopLogWorker()
2323
}
2424

25+
// PutRecordOrDrop put record
2526
func PutRecordOrDrop(record string) {
2627
select {
2728
case RecordLogger.recordChan <- record:

util/logutil/record_replayer.go

Lines changed: 0 additions & 95 deletions
This file was deleted.

util/replayutil/record_replayer.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package replayutil
2+
3+
import (
4+
"bufio"
5+
"context"
6+
"fmt"
7+
"os"
8+
"strconv"
9+
"strings"
10+
"time"
11+
12+
"github.com/pingcap/errors"
13+
"github.com/pingcap/log"
14+
"github.com/pingcap/tidb/kv"
15+
"github.com/pingcap/tidb/session"
16+
)
17+
18+
// RecordReplayer is used to replay sql
19+
var RecordReplayer *recordReplayer
20+
// Sessions is a map
21+
var Sessions map[string]session.Session
22+
23+
// StartReplay starts replay
24+
func StartReplay(filename string, store kv.Storage) {
25+
RecordReplayer = newRecordPlayer(filename, store)
26+
go RecordReplayer.start()
27+
}
28+
29+
// StopReplay stops replay
30+
func StopReplay() {
31+
RecordReplayer.close <- struct{}{}
32+
}
33+
34+
func newRecordPlayer(filename string, store kv.Storage) *recordReplayer {
35+
r := &recordReplayer{
36+
store: store,
37+
fileName: filename,
38+
close: make(chan struct{}),
39+
}
40+
return r
41+
}
42+
43+
type recordReplayer struct {
44+
store kv.Storage
45+
close chan struct{}
46+
fileName string
47+
scanner *bufio.Scanner
48+
}
49+
50+
func (r *recordReplayer) start() {
51+
f, err := os.OpenFile(r.fileName, os.O_RDONLY, os.ModePerm)
52+
defer f.Close()
53+
if err != nil {
54+
fmt.Printf("Open file error %s\n", err.Error())
55+
return
56+
}
57+
58+
r.scanner = bufio.NewScanner(f)
59+
Sessions = make(map[string]session.Session)
60+
start := time.Now()
61+
for r.scanner.Scan() {
62+
select {
63+
case <-r.close:
64+
break
65+
default:
66+
}
67+
text := r.scanner.Text()
68+
record := strings.SplitN(text, " ", 4)
69+
if len(record) < 4 {
70+
fmt.Printf("invalid sql log %v, len:%d\n", record, len(record))
71+
continue
72+
}
73+
ts, _ := strconv.ParseFloat(record[1], 10)
74+
if sleepTime := ts - time.Since(start).Seconds(); sleepTime > 0 {
75+
fmt.Printf("sleep time:%v\n", sleepTime)
76+
time.Sleep(time.Duration(sleepTime) * time.Second)
77+
}
78+
if s, exist := Sessions[record[0]]; !exist {
79+
se, err := session.CreateSession(r.store)
80+
se.GetSessionVars().CurrentDB = record[2]
81+
if err != nil {
82+
log.Info("init replay session fail")
83+
return
84+
}
85+
Sessions[record[0]] = se
86+
go replayExecuteSQL(record[3], se, record[0])
87+
} else {
88+
go replayExecuteSQL(record[3], s, record[0])
89+
}
90+
}
91+
}
92+
93+
func replayExecuteSQL(sql string, s session.Session, connection string) error {
94+
ctx := context.Background()
95+
stmts, err := s.Parse(ctx, sql)
96+
if err != nil {
97+
return err
98+
}
99+
for _, stmt := range stmts {
100+
_, err := s.ExecuteStmt(ctx, stmt)
101+
if err != nil {
102+
return errors.Trace(err)
103+
}
104+
}
105+
return nil
106+
}

0 commit comments

Comments
 (0)