Skip to content

Commit 25debf4

Browse files
committed
UPDATE 2025.02.05
1 parent 0910f75 commit 25debf4

File tree

11 files changed

+170
-66
lines changed

11 files changed

+170
-66
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Sysbench golang version
66

77
# Incompatibility with sysbench
88

9+
## Database benchmark only
10+
911
## Few options
1012

1113
## Number of reconnects is not supported
@@ -14,4 +16,4 @@ Sysbench golang version
1416

1517
# Additional feature
1618

17-
## Spanner driver
19+
## Google Cloud Spanner

benchmark/benchmark.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
package benchmark
22

3+
import "context"
4+
5+
const (
6+
DBDriverMySQL = "mysql"
7+
DBDriverPgSQL = "pgsql"
8+
DBDriverSpanner = "spanner"
9+
)
10+
311
type (
412
Benchmark interface {
5-
Init() error
13+
Init(context.Context) error
614
Done() error
7-
Prepare() error
8-
Event() (uint64, uint64, uint64, uint64, error)
15+
Prepare(context.Context) error
16+
Event(context.Context) (uint64, uint64, uint64, uint64, error)
917
}
1018
CommonOpts struct {
1119
Tables int `long:"tables" description:"number of tables" default:"1"`
@@ -16,14 +24,15 @@ type (
1624
BenchmarkOpts struct {
1725
CommonOpts
1826
MySQLOpts
27+
PgSQLOpts
1928
SpannerOpts
2029
}
2130
)
2231

2332
func BenchmarkFactory(opt *BenchmarkOpts) Benchmark {
24-
if opt.DBDriver == "spanner" {
33+
if opt.DBDriver == DBDriverSpanner {
2534
return newSpannerOLTP(opt)
2635
} else {
27-
return newMySQLOLTP(opt)
36+
return newOLTPBench(opt)
2837
}
2938
}
Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package benchmark
22

33
import (
4+
"context"
45
"database/sql"
56
"fmt"
67
"math/rand"
78
"strings"
89

910
_ "github.com/go-sql-driver/mysql"
11+
_ "github.com/lib/pq"
12+
_ "github.com/samitani/go-sysbench/driver"
1013
)
1114

1215
const (
@@ -63,19 +66,43 @@ type (
6366
MySQLDB string `long:"mysql-db" description:"MySQL database name" default:"sbtest"`
6467
}
6568

66-
MySQLOLTP struct {
69+
PgSQLOpts struct {
70+
PgSQLHost string `long:"pgsql-host" description:"PostgreSQL server host" default:"localhost"`
71+
PgSQLPort int `long:"pgsql-port" description:"PostgreSQL server port" default:"5432"`
72+
PgSQLUser string `long:"pgsql-user" description:"PostgreSQL user" default:"sbtest"`
73+
PgSQLPassword string `long:"pgsql-password" env:"PGPASSWORD" description:"PostgreSQL password" default:""`
74+
PgSQLDB string `long:"pgsql-db" description:"PostgreSQL database name" default:"sbtest"`
75+
}
76+
77+
OLTPBench struct {
6778
opts *BenchmarkOpts
6879

6980
db *sql.DB
7081
}
7182
)
7283

73-
func newMySQLOLTP(option *BenchmarkOpts) *MySQLOLTP {
74-
return &MySQLOLTP{opts: option}
84+
func newOLTPBench(option *BenchmarkOpts) *OLTPBench {
85+
return &OLTPBench{opts: option}
7586
}
7687

77-
func (o *MySQLOLTP) Init() error {
78-
db, err := sql.Open("mysql", o.dsn())
88+
func (o *OLTPBench) Init(ctx context.Context) error {
89+
var drvName string
90+
var dsn string
91+
92+
if o.opts.DBDriver == DBDriverMySQL {
93+
drvName = "mysql"
94+
dsn = o.dsnMySQL()
95+
} else if o.opts.DBDriver == DBDriverPgSQL {
96+
drvName = "postgres"
97+
dsn = o.dsnPgSQL()
98+
}
99+
100+
db, err := sql.Open(drvName, dsn)
101+
if err != nil {
102+
return err
103+
}
104+
105+
err = db.Ping()
79106
if err != nil {
80107
return err
81108
}
@@ -85,15 +112,15 @@ func (o *MySQLOLTP) Init() error {
85112
return nil
86113
}
87114

88-
func (o *MySQLOLTP) Prepare() error {
115+
func (o *OLTPBench) Prepare(ctx context.Context) error {
89116
err := o.createTable()
90117
if err != nil {
91118
return err
92119
}
93120
return nil
94121
}
95122

96-
func (o *MySQLOLTP) Event() (reads uint64, writes uint64, others uint64, errors uint64, e error) {
123+
func (o *OLTPBench) Event(ctx context.Context) (reads uint64, writes uint64, others uint64, errors uint64, e error) {
97124
var numReads, numWrites, numOthers uint64
98125
var tableNum = o.getRandTableNum()
99126
var numRowReturn = 0
@@ -106,7 +133,7 @@ func (o *MySQLOLTP) Event() (reads uint64, writes uint64, others uint64, errors
106133
numOthers += 1
107134

108135
for i := 0; i < numPointSelects; i++ {
109-
rows, err := tx.Query(fmt.Sprintf(stmtPointSelects, tableNum, sbRand(0, o.opts.TableSize)))
136+
rows, err := tx.QueryContext(ctx, fmt.Sprintf(stmtPointSelects, tableNum, sbRand(0, o.opts.TableSize)))
110137
if err != nil {
111138
tx.Rollback()
112139
return numReads, numWrites, numOthers, 1, err
@@ -119,7 +146,7 @@ func (o *MySQLOLTP) Event() (reads uint64, writes uint64, others uint64, errors
119146

120147
for i := 0; i < numSimpleRanges; i++ {
121148
begin := sbRand(0, o.opts.TableSize)
122-
rows, err := tx.Query(fmt.Sprintf(stmtSimpleRanges, tableNum, begin, begin+rangeSize-1))
149+
rows, err := tx.QueryContext(ctx, fmt.Sprintf(stmtSimpleRanges, tableNum, begin, begin+rangeSize-1))
123150
if err != nil {
124151
tx.Rollback()
125152
return numReads, numWrites, numOthers, 1, err
@@ -132,7 +159,7 @@ func (o *MySQLOLTP) Event() (reads uint64, writes uint64, others uint64, errors
132159

133160
for i := 0; i < numSumRanges; i++ {
134161
begin := sbRand(0, o.opts.TableSize)
135-
rows, err := tx.Query(fmt.Sprintf(stmtSumRanges, tableNum, begin, begin+rangeSize-1))
162+
rows, err := tx.QueryContext(ctx, fmt.Sprintf(stmtSumRanges, tableNum, begin, begin+rangeSize-1))
136163
if err != nil {
137164
tx.Rollback()
138165
return numReads, numWrites, numOthers, 1, err
@@ -145,7 +172,7 @@ func (o *MySQLOLTP) Event() (reads uint64, writes uint64, others uint64, errors
145172

146173
for i := 0; i < numOrderRanges; i++ {
147174
begin := sbRand(0, o.opts.TableSize)
148-
rows, err := tx.Query(fmt.Sprintf(stmtOrderRanges, tableNum, begin, begin+rangeSize-1))
175+
rows, err := tx.QueryContext(ctx, fmt.Sprintf(stmtOrderRanges, tableNum, begin, begin+rangeSize-1))
149176
if err != nil {
150177
tx.Rollback()
151178
return numReads, numWrites, numOthers, 1, err
@@ -158,7 +185,7 @@ func (o *MySQLOLTP) Event() (reads uint64, writes uint64, others uint64, errors
158185

159186
for i := 0; i < numDistinctRanges; i++ {
160187
begin := sbRand(0, o.opts.TableSize)
161-
rows, err := tx.Query(fmt.Sprintf(stmtDistinctRanges, tableNum, begin, begin+rangeSize-1))
188+
rows, err := tx.QueryContext(ctx, fmt.Sprintf(stmtDistinctRanges, tableNum, begin, begin+rangeSize-1))
162189
if err != nil {
163190
tx.Rollback()
164191
return numReads, numWrites, numOthers, 1, err
@@ -171,15 +198,15 @@ func (o *MySQLOLTP) Event() (reads uint64, writes uint64, others uint64, errors
171198

172199
if o.opts.ReadWrite {
173200
for i := 0; i < numIndexUpdates; i++ {
174-
_, err := tx.Exec(fmt.Sprintf(stmtIndexUpdates, tableNum, sbRand(0, o.opts.TableSize)))
201+
_, err := tx.ExecContext(ctx, fmt.Sprintf(stmtIndexUpdates, tableNum, sbRand(0, o.opts.TableSize)))
175202
if err != nil {
176203
tx.Rollback()
177204
return numReads, numWrites, numOthers, 1, err
178205
}
179206
numWrites += 1
180207
}
181208
for i := 0; i < numNonIndexUpdates; i++ {
182-
_, err := tx.Exec(fmt.Sprintf(stmtNonIndex_updates, tableNum, getCValue(), sbRand(0, o.opts.TableSize)))
209+
_, err := tx.ExecContext(ctx, fmt.Sprintf(stmtNonIndex_updates, tableNum, getCValue(), sbRand(0, o.opts.TableSize)))
183210
if err != nil {
184211
tx.Rollback()
185212
return numReads, numWrites, numOthers, 1, err
@@ -189,14 +216,14 @@ func (o *MySQLOLTP) Event() (reads uint64, writes uint64, others uint64, errors
189216
for i := 0; i < numDeleteInserts; i++ {
190217
id := sbRand(0, o.opts.TableSize)
191218

192-
_, err := tx.Exec(fmt.Sprintf(stmtDeletes, tableNum, id))
219+
_, err := tx.ExecContext(ctx, fmt.Sprintf(stmtDeletes, tableNum, id))
193220
if err != nil {
194221
tx.Rollback()
195222
return numReads, numWrites, numOthers, 1, err
196223
}
197224
numWrites += 1
198225

199-
_, err = tx.Exec(fmt.Sprintf(stmtInserts, tableNum, id, sbRand(0, o.opts.TableSize), getCValue(), getPadValue()))
226+
_, err = tx.ExecContext(ctx, fmt.Sprintf(stmtInserts, tableNum, id, sbRand(0, o.opts.TableSize), getCValue(), getPadValue()))
200227
if err != nil {
201228
tx.Rollback()
202229
return numReads, numWrites, numOthers, 1, err
@@ -215,16 +242,20 @@ func (o *MySQLOLTP) Event() (reads uint64, writes uint64, others uint64, errors
215242
return numReads, numWrites, numOthers, 0, nil
216243
}
217244

218-
func (o *MySQLOLTP) Done() error {
245+
func (o *OLTPBench) Done() error {
219246
o.db.Close()
220247
return nil
221248
}
222249

223-
func (o *MySQLOLTP) dsn() string {
250+
func (o *OLTPBench) dsnMySQL() string {
224251
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", o.opts.MySQLUser, o.opts.MySQLPassword, o.opts.MySQLHost, o.opts.MySQLPort, o.opts.MySQLDB)
225252
}
226253

227-
func (o *MySQLOLTP) getRandTableNum() int {
254+
func (o *OLTPBench) dsnPgSQL() string {
255+
return fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable", o.opts.PgSQLUser, o.opts.PgSQLPassword, o.opts.PgSQLHost, o.opts.PgSQLPort, o.opts.PgSQLDB)
256+
}
257+
258+
func (o *OLTPBench) getRandTableNum() int {
228259
return sbRand(1, o.opts.Tables)
229260
}
230261

@@ -256,8 +287,15 @@ func sbRandStr(format string) string {
256287
return string(buf)
257288
}
258289

259-
func (o *MySQLOLTP) createTable() error {
260-
idDef := "INT NOT NULL AUTO_INCREMENT"
290+
func (o *OLTPBench) createTable() error {
291+
var idDef string
292+
293+
if o.opts.DBDriver == DBDriverPgSQL {
294+
idDef = "INT NOT NULL"
295+
} else {
296+
idDef = "INT NOT NULL AUTO_INCREMENT"
297+
}
298+
261299
idIndexDef := "PRIMARY KEY"
262300
engineDef := ""
263301
extraTableOptions := ""
@@ -278,10 +316,10 @@ func (o *MySQLOLTP) createTable() error {
278316

279317
fmt.Printf("Inserting %d records into 'sbtest%d'\n", o.opts.TableSize, tableNum)
280318
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()))
319+
for i := 1; i <= o.opts.TableSize; i++ {
320+
insertValues = append(insertValues, fmt.Sprintf(`(%d, %d, '%s', '%s') `, i, sbRand(0, o.opts.TableSize), getCValue(), getPadValue()))
283321
}
284-
query = fmt.Sprintf("INSERT INTO sbtest%d (k, c, pad) VALUES", tableNum) + strings.Join(insertValues, ",")
322+
query = fmt.Sprintf("INSERT INTO sbtest%d (id, k, c, pad) VALUES", tableNum) + strings.Join(insertValues, ",")
285323
_, err = o.db.Exec(query)
286324
if err != nil {
287325
return err

benchmark/spanner_oltp.go

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
)
1515

1616
const (
17-
stmtSpannerPointSelects = "SELECT c FROM sbtest%d WHERE id=%d"
17+
stmtSpannerPointSelects = "SELECT c FROM sbtest%d WHERE id=@Id"
1818
stmtSpannerSimpleRanges = "SELECT c FROM sbtest%d WHERE id BETWEEN %d AND %d"
1919
stmtSpannerSumRanges = "SELECT SUM(k) FROM sbtest%d WHERE id BETWEEN %d AND %d"
2020
stmtSpannerOrderRanges = "SELECT c FROM sbtest%d WHERE id BETWEEN %d AND %d ORDER BY c"
@@ -35,19 +35,15 @@ type (
3535
SpannerOLTP struct {
3636
opts *BenchmarkOpts
3737
db *spanner.Client
38-
ctx context.Context
3938
}
4039
)
4140

4241
func newSpannerOLTP(option *BenchmarkOpts) *SpannerOLTP {
4342
return &SpannerOLTP{opts: option}
4443
}
4544

46-
func (s *SpannerOLTP) Init() error {
47-
ctx := context.TODO()
48-
s.ctx = ctx
49-
50-
client, err := spanner.NewClient(s.ctx, s.dsn())
45+
func (s *SpannerOLTP) Init(ctx context.Context) error {
46+
client, err := spanner.NewClient(ctx, s.dsn())
5147
if err != nil {
5248
return err
5349
}
@@ -56,8 +52,8 @@ func (s *SpannerOLTP) Init() error {
5652
return nil
5753
}
5854

59-
func (s *SpannerOLTP) Prepare() error {
60-
err := s.createTable()
55+
func (s *SpannerOLTP) Prepare(ctx context.Context) error {
56+
err := s.createTable(ctx)
6157
if err != nil {
6258
return err
6359
}
@@ -68,14 +64,15 @@ func (s *SpannerOLTP) getRandTableNum() int {
6864
return sbRand(1, s.opts.Tables)
6965
}
7066

71-
func (s *SpannerOLTP) Event() (reads uint64, writes uint64, others uint64, errors uint64, e error) {
67+
func (s *SpannerOLTP) Event(ctx context.Context) (reads uint64, writes uint64, others uint64, errors uint64, e error) {
7268
var tableNum = s.getRandTableNum()
7369
var numReads uint64
7470

75-
_, err := s.db.ReadWriteTransaction(s.ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
71+
_, err := s.db.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
7672
for i := 0; i < numPointSelects; i++ {
7773
stmt := spanner.Statement{
78-
SQL: fmt.Sprintf(stmtSpannerPointSelects, tableNum, sbRand(0, s.opts.TableSize)),
74+
SQL: fmt.Sprintf(stmtSpannerPointSelects, tableNum),
75+
Params: map[string]interface{}{"Id": sbRand(0, s.opts.TableSize)},
7976
}
8077
_, err := txn.Query(ctx, stmt).Next()
8178
if err != nil && err != iterator.Done {
@@ -97,8 +94,7 @@ func (s *SpannerOLTP) dsn() string {
9794
return fmt.Sprintf("projects/%s/instances/%s/databases/%s", s.opts.SpannerProjectId, s.opts.SpannerInstanceId, s.opts.SpannerDB)
9895
}
9996

100-
func (s *SpannerOLTP) createTable() error {
101-
ctx := context.TODO()
97+
func (s *SpannerOLTP) createTable(ctx context.Context) error {
10298
adminClient, err := database.NewDatabaseAdminClient(ctx)
10399

104100
if err != nil {
@@ -134,7 +130,7 @@ func (s *SpannerOLTP) createTable() error {
134130
}
135131
query := fmt.Sprintf("INSERT INTO sbtest%d (id, k, c, pad) VALUES", tableNum) + strings.Join(insertValues, ",")
136132

137-
_, err = s.db.ReadWriteTransaction(s.ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
133+
_, err = s.db.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
138134
stmt := spanner.Statement{
139135
SQL: query,
140136
}

cmd/main.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
package main
22

3-
// TODO later
4-
// 1. PostgreSQL 対応
5-
// 2. Spannerのシナリオの作成
6-
// 3. カスタムシナリオを書く
7-
// 4. 乱数生成をクエリを投げる前段階で行う
8-
// 5. thread fairness の計算
9-
// 6. README を書く
10-
// 7. Context をちゃんと引き回す
11-
// 8. 空振りクエリはotherにカウントする
12-
// 9. PreparedStatement の実装
13-
// 10. banner の実装
14-
// 11. コミットに失敗した場合、Reads/Writes/Other にカウントするかそれとも全部エラーにカウントするか
15-
// 12. Spanner Session Pool の様子を観測する
3+
// TODO
4+
// 1. Spanner Session Pool の様子を観測する
5+
// 2. パフォーマンス差分を埋める
6+
// 2-2. thread fairness の計算
7+
// 3. SSL/ON OFF
8+
9+
// 5. Spannerのシナリオの作成
10+
// 5-2. PostgreSQL の DSN のエスケープ
11+
// 5-3. 空振りクエリはotherにカウントする
12+
// 5-4. Spannerのパラメータクエリが有効化できていることを確認する
13+
14+
// 6. 乱数生成をクエリを投げる前段階で行う
15+
// 11. PreparedStatement の実装
16+
17+
// 7. README を書く
18+
// 10. カスタムシナリオを書く
1619

1720
import (
1821
"log"

driver/driver.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package driver
2+
3+
type (
4+
Driver interface {
5+
Open(string)
6+
ExecuteTransaction([]string)
7+
Close()
8+
}
9+
)

0 commit comments

Comments
 (0)