Skip to content

Commit 0910f75

Browse files
committed
UPDATE 2025.02.04
1 parent 54a7c14 commit 0910f75

File tree

21 files changed

+2783
-177
lines changed

21 files changed

+2783
-177
lines changed

Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.PHONY: build
2+
build:
3+
go build -trimpath -o go-sysbench cmd/main.go
4+
5+
.PHONY: lint
6+
lint:
7+
golangci-lint run -v
8+
go vet -vettool=$HOME/go/bin/zagane ./...
9+
10+
.PHONY: test
11+
test:
12+
go test -v ./...

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Sysbench golang version
2+
3+
# Usage
4+
5+
## How to install
6+
7+
# Incompatibility with sysbench
8+
9+
## Few options
10+
11+
## Number of reconnects is not supported
12+
13+
## Lua script is not supported
14+
15+
# Additional feature
16+
17+
## Spanner driver

README_ja.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Sysbench golang version

benchmark/benchmark.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package benchmark
2+
3+
type (
4+
Benchmark interface {
5+
Init() error
6+
Done() error
7+
Prepare() error
8+
Event() (uint64, uint64, uint64, uint64, error)
9+
}
10+
CommonOpts struct {
11+
Tables int `long:"tables" description:"number of tables" default:"1"`
12+
TableSize int `long:"table_size" description:"number of rows per table" default:"10000"`
13+
DBDriver string `long:"db-driver" choice:"mysql" choice:"pgsql" choice:"spanner" description:"specifies database driver to use" default:"mysql"` //nolint:staticcheck
14+
ReadWrite bool
15+
}
16+
BenchmarkOpts struct {
17+
CommonOpts
18+
MySQLOpts
19+
SpannerOpts
20+
}
21+
)
22+
23+
func BenchmarkFactory(opt *BenchmarkOpts) Benchmark {
24+
if opt.DBDriver == "spanner" {
25+
return newSpannerOLTP(opt)
26+
} else {
27+
return newMySQLOLTP(opt)
28+
}
29+
}

benchmark/mysql_oltp.go

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
package benchmark
2+
3+
import (
4+
"database/sql"
5+
"fmt"
6+
"math/rand"
7+
"strings"
8+
9+
_ "github.com/go-sql-driver/mysql"
10+
)
11+
12+
const (
13+
stmtPointSelects = "SELECT c FROM sbtest%d WHERE id=%d"
14+
stmtSimpleRanges = "SELECT c FROM sbtest%d WHERE id BETWEEN %d AND %d"
15+
stmtSumRanges = "SELECT SUM(k) FROM sbtest%d WHERE id BETWEEN %d AND %d"
16+
stmtOrderRanges = "SELECT c FROM sbtest%d WHERE id BETWEEN %d AND %d ORDER BY c"
17+
stmtDistinctRanges = "SELECT DISTINCT c FROM sbtest%d WHERE id BETWEEN %d AND %d ORDER BY c"
18+
stmtIndexUpdates = "UPDATE sbtest%d SET k=k+1 WHERE id=%d"
19+
stmtNonIndex_updates = "UPDATE sbtest%d SET c=%s WHERE id=%d"
20+
stmtDeletes = "DELETE FROM sbtest%d WHERE id=%d"
21+
stmtInserts = "INSERT INTO sbtest%d (id, k, c, pad) VALUES (%d, %d, %s, %s)"
22+
23+
// https://github.com/akopytov/sysbench/blob/1.0.20/src/lua/oltp_common.lua#L36-L37
24+
// Range size for range SELECT queries
25+
rangeSize = 100
26+
27+
// https://github.com/akopytov/sysbench/blob/1.0.20/src/lua/oltp_common.lua#L40-L41
28+
// Number of point SELECT queries per transaction
29+
numPointSelects = 10
30+
31+
// https://github.com/akopytov/sysbench/blob/1.0.20/src/lua/oltp_common.lua#L42-L43
32+
// Number of simple range SELECT queries per transaction
33+
numSimpleRanges = 1
34+
35+
// https://github.com/akopytov/sysbench/blob/1.0.20/src/lua/oltp_common.lua#L44-L45
36+
// Number of SELECT SUM() queries per transaction
37+
numSumRanges = 1
38+
39+
// https://github.com/akopytov/sysbench/blob/1.0.20/src/lua/oltp_common.lua#L46-L47
40+
// Number of SELECT ORDER BY queries per transaction
41+
numOrderRanges = 1
42+
43+
// https://github.com/akopytov/sysbench/blob/1.0.20/src/lua/oltp_common.lua#L48-L49
44+
// Number of SELECT DISTINCT queries per transaction
45+
numDistinctRanges = 1
46+
47+
// Number of UPDATE index queries per transaction
48+
numIndexUpdates = 1
49+
50+
// Number of UPDATE non-index queries per transaction
51+
numNonIndexUpdates = 1
52+
53+
// Number of DELETE/INSERT combinations per transaction
54+
numDeleteInserts = 1
55+
)
56+
57+
type (
58+
MySQLOpts struct {
59+
MySQLHost string `long:"mysql-host" description:"MySQL server host" default:"localhost"`
60+
MySQLPort int `long:"mysql-port" description:"MySQL server port" default:"3306"`
61+
MySQLUser string `long:"mysql-user" description:"MySQL user" default:"sbtest"`
62+
MySQLPassword string `long:"mysql-password" env:"MYSQL_PWD" description:"MySQL password" default:""`
63+
MySQLDB string `long:"mysql-db" description:"MySQL database name" default:"sbtest"`
64+
}
65+
66+
MySQLOLTP struct {
67+
opts *BenchmarkOpts
68+
69+
db *sql.DB
70+
}
71+
)
72+
73+
func newMySQLOLTP(option *BenchmarkOpts) *MySQLOLTP {
74+
return &MySQLOLTP{opts: option}
75+
}
76+
77+
func (o *MySQLOLTP) Init() error {
78+
db, err := sql.Open("mysql", o.dsn())
79+
if err != nil {
80+
return err
81+
}
82+
83+
o.db = db
84+
85+
return nil
86+
}
87+
88+
func (o *MySQLOLTP) Prepare() error {
89+
err := o.createTable()
90+
if err != nil {
91+
return err
92+
}
93+
return nil
94+
}
95+
96+
func (o *MySQLOLTP) Event() (reads uint64, writes uint64, others uint64, errors uint64, e error) {
97+
var numReads, numWrites, numOthers uint64
98+
var tableNum = o.getRandTableNum()
99+
var numRowReturn = 0
100+
101+
tx, err := o.db.Begin()
102+
103+
if err != nil {
104+
return 0, 0, 0, 1, err
105+
}
106+
numOthers += 1
107+
108+
for i := 0; i < numPointSelects; i++ {
109+
rows, err := tx.Query(fmt.Sprintf(stmtPointSelects, tableNum, sbRand(0, o.opts.TableSize)))
110+
if err != nil {
111+
tx.Rollback()
112+
return numReads, numWrites, numOthers, 1, err
113+
}
114+
for rows.Next() {
115+
numRowReturn += 1
116+
}
117+
numReads += 1
118+
}
119+
120+
for i := 0; i < numSimpleRanges; i++ {
121+
begin := sbRand(0, o.opts.TableSize)
122+
rows, err := tx.Query(fmt.Sprintf(stmtSimpleRanges, tableNum, begin, begin+rangeSize-1))
123+
if err != nil {
124+
tx.Rollback()
125+
return numReads, numWrites, numOthers, 1, err
126+
}
127+
for rows.Next() {
128+
numRowReturn += 1
129+
}
130+
numReads += 1
131+
}
132+
133+
for i := 0; i < numSumRanges; i++ {
134+
begin := sbRand(0, o.opts.TableSize)
135+
rows, err := tx.Query(fmt.Sprintf(stmtSumRanges, tableNum, begin, begin+rangeSize-1))
136+
if err != nil {
137+
tx.Rollback()
138+
return numReads, numWrites, numOthers, 1, err
139+
}
140+
for rows.Next() {
141+
numRowReturn += 1
142+
}
143+
numReads += 1
144+
}
145+
146+
for i := 0; i < numOrderRanges; i++ {
147+
begin := sbRand(0, o.opts.TableSize)
148+
rows, err := tx.Query(fmt.Sprintf(stmtOrderRanges, tableNum, begin, begin+rangeSize-1))
149+
if err != nil {
150+
tx.Rollback()
151+
return numReads, numWrites, numOthers, 1, err
152+
}
153+
for rows.Next() {
154+
numRowReturn += 1
155+
}
156+
numReads += 1
157+
}
158+
159+
for i := 0; i < numDistinctRanges; i++ {
160+
begin := sbRand(0, o.opts.TableSize)
161+
rows, err := tx.Query(fmt.Sprintf(stmtDistinctRanges, tableNum, begin, begin+rangeSize-1))
162+
if err != nil {
163+
tx.Rollback()
164+
return numReads, numWrites, numOthers, 1, err
165+
}
166+
for rows.Next() {
167+
numRowReturn += 1
168+
}
169+
numReads += 1
170+
}
171+
172+
if o.opts.ReadWrite {
173+
for i := 0; i < numIndexUpdates; i++ {
174+
_, err := tx.Exec(fmt.Sprintf(stmtIndexUpdates, tableNum, sbRand(0, o.opts.TableSize)))
175+
if err != nil {
176+
tx.Rollback()
177+
return numReads, numWrites, numOthers, 1, err
178+
}
179+
numWrites += 1
180+
}
181+
for i := 0; i < numNonIndexUpdates; i++ {
182+
_, err := tx.Exec(fmt.Sprintf(stmtNonIndex_updates, tableNum, getCValue(), sbRand(0, o.opts.TableSize)))
183+
if err != nil {
184+
tx.Rollback()
185+
return numReads, numWrites, numOthers, 1, err
186+
}
187+
numWrites += 1
188+
}
189+
for i := 0; i < numDeleteInserts; i++ {
190+
id := sbRand(0, o.opts.TableSize)
191+
192+
_, err := tx.Exec(fmt.Sprintf(stmtDeletes, tableNum, id))
193+
if err != nil {
194+
tx.Rollback()
195+
return numReads, numWrites, numOthers, 1, err
196+
}
197+
numWrites += 1
198+
199+
_, err = tx.Exec(fmt.Sprintf(stmtInserts, tableNum, id, sbRand(0, o.opts.TableSize), getCValue(), getPadValue()))
200+
if err != nil {
201+
tx.Rollback()
202+
return numReads, numWrites, numOthers, 1, err
203+
}
204+
numWrites += 1
205+
}
206+
207+
}
208+
209+
err = tx.Commit()
210+
if err != nil {
211+
return numReads, numWrites, numOthers, 1, err
212+
}
213+
numOthers += 1
214+
215+
return numReads, numWrites, numOthers, 0, nil
216+
}
217+
218+
func (o *MySQLOLTP) Done() error {
219+
o.db.Close()
220+
return nil
221+
}
222+
223+
func (o *MySQLOLTP) dsn() string {
224+
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", o.opts.MySQLUser, o.opts.MySQLPassword, o.opts.MySQLHost, o.opts.MySQLPort, o.opts.MySQLDB)
225+
}
226+
227+
func (o *MySQLOLTP) getRandTableNum() int {
228+
return sbRand(1, o.opts.Tables)
229+
}
230+
231+
func getCValue() string {
232+
// 10 groups, 119 characters
233+
return sbRandStr("###########-###########-###########-###########-###########-###########-###########-###########-###########-###########")
234+
}
235+
236+
func getPadValue() string {
237+
return sbRandStr("###########-###########-###########-###########-###########")
238+
}
239+
240+
func sbRand(minimum int, maximum int) int {
241+
return rand.Intn(maximum-minimum+1) + minimum
242+
}
243+
244+
func sbRandStr(format string) string {
245+
buf := make([]rune, len(format))
246+
for i, c := range format {
247+
if c == '#' {
248+
buf[i] = rune(sbRand(int('0'), int('9')))
249+
} else if c == '@' {
250+
buf[i] = rune(sbRand(int('a'), int('z')))
251+
} else {
252+
buf[i] = c
253+
}
254+
}
255+
256+
return string(buf)
257+
}
258+
259+
func (o *MySQLOLTP) createTable() error {
260+
idDef := "INT NOT NULL AUTO_INCREMENT"
261+
idIndexDef := "PRIMARY KEY"
262+
engineDef := ""
263+
extraTableOptions := ""
264+
265+
for tableNum := 1; tableNum <= o.opts.Tables; tableNum++ {
266+
fmt.Printf("Creating table 'sbtest%d'...\n", tableNum)
267+
query := fmt.Sprintf(`CREATE TABLE sbtest%d(
268+
id %s,
269+
k INTEGER DEFAULT '0' NOT NULL,
270+
c CHAR(120) DEFAULT '' NOT NULL,
271+
pad CHAR(60) DEFAULT '' NOT NULL,
272+
%s (id)
273+
) %s %s`, tableNum, idDef, idIndexDef, engineDef, extraTableOptions)
274+
_, err := o.db.Exec(query)
275+
if err != nil {
276+
return err
277+
}
278+
279+
fmt.Printf("Inserting %d records into 'sbtest%d'\n", o.opts.TableSize, tableNum)
280+
insertValues := []string{}
281+
for i := 0; i < o.opts.TableSize; i++ {
282+
insertValues = append(insertValues, fmt.Sprintf(`(%d, "%s", "%s") `, sbRand(0, o.opts.TableSize), getCValue(), getPadValue()))
283+
}
284+
query = fmt.Sprintf("INSERT INTO sbtest%d (k, c, pad) VALUES", tableNum) + strings.Join(insertValues, ",")
285+
_, err = o.db.Exec(query)
286+
if err != nil {
287+
return err
288+
}
289+
290+
fmt.Printf("Creating a secondary index on 'sbtest%d'...\n", tableNum)
291+
query = fmt.Sprintf("CREATE INDEX k_%d ON sbtest%d(k)", tableNum, tableNum)
292+
_, err = o.db.Exec(query)
293+
if err != nil {
294+
return err
295+
}
296+
}
297+
298+
return nil
299+
}

0 commit comments

Comments
 (0)