Skip to content

Commit dedf72e

Browse files
authored
Merge pull request #471 from dtm-labs/alpha
use a new algorithm to do lock one trans
2 parents e704733 + a5f0ae1 commit dedf72e

File tree

3 files changed

+67
-60
lines changed

3 files changed

+67
-60
lines changed

dtmsvr/storage/boltdb/boltdb_test.go

+46-46
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"testing"
1212
"time"
1313

14-
. "github.com/onsi/gomega"
14+
ga "github.com/onsi/gomega"
1515
bolt "go.etcd.io/bbolt"
1616

1717
"github.com/dtm-labs/dtm/client/dtmcli/dtmimp"
@@ -20,13 +20,13 @@ import (
2020

2121
func TestInitializeBuckets(t *testing.T) {
2222
t.Run("normal test", func(t *testing.T) {
23-
g := NewWithT(t)
23+
g := ga.NewWithT(t)
2424
db, err := bolt.Open(path.Join(t.TempDir(), "./test.bolt"), 0666, &bolt.Options{Timeout: 1 * time.Second})
25-
g.Expect(err).ToNot(HaveOccurred())
25+
g.Expect(err).ToNot(ga.HaveOccurred())
2626
defer db.Close()
2727

2828
err = initializeBuckets(db)
29-
g.Expect(err).ToNot(HaveOccurred())
29+
g.Expect(err).ToNot(ga.HaveOccurred())
3030

3131
actualBuckets := [][]byte{}
3232
err = db.View(func(t *bolt.Tx) error {
@@ -35,42 +35,42 @@ func TestInitializeBuckets(t *testing.T) {
3535
return nil
3636
})
3737
})
38-
g.Expect(err).ToNot(HaveOccurred())
38+
g.Expect(err).ToNot(ga.HaveOccurred())
3939

40-
g.Expect(actualBuckets).To(Equal(allBuckets))
40+
g.Expect(actualBuckets).To(ga.Equal(allBuckets))
4141
})
4242
}
4343

4444
func TestCleanupExpiredData(t *testing.T) {
4545
t.Run("negative expired seconds", func(t *testing.T) {
46-
g := NewWithT(t)
46+
g := ga.NewWithT(t)
4747
db, err := bolt.Open(path.Join(t.TempDir(), "./test.bolt"), 0666, &bolt.Options{Timeout: 1 * time.Second})
48-
g.Expect(err).ToNot(HaveOccurred())
48+
g.Expect(err).ToNot(ga.HaveOccurred())
4949
defer db.Close()
5050

5151
err = cleanupExpiredData(-1*time.Second, db)
52-
g.Expect(err).ToNot(HaveOccurred())
52+
g.Expect(err).ToNot(ga.HaveOccurred())
5353
})
5454

5555
t.Run("nil global bucket", func(t *testing.T) {
56-
g := NewWithT(t)
56+
g := ga.NewWithT(t)
5757
db, err := bolt.Open(path.Join(t.TempDir(), "./test.bolt"), 0666, &bolt.Options{Timeout: 1 * time.Second})
58-
g.Expect(err).ToNot(HaveOccurred())
58+
g.Expect(err).ToNot(ga.HaveOccurred())
5959
defer db.Close()
6060

6161
err = cleanupExpiredData(time.Second, db)
62-
g.Expect(err).ToNot(HaveOccurred())
62+
g.Expect(err).ToNot(ga.HaveOccurred())
6363
})
6464

6565
t.Run("normal test", func(t *testing.T) {
66-
g := NewWithT(t)
66+
g := ga.NewWithT(t)
6767
db, err := bolt.Open(path.Join(t.TempDir(), "./test.bolt"), 0666, &bolt.Options{Timeout: 1 * time.Second})
68-
g.Expect(err).ToNot(HaveOccurred())
68+
g.Expect(err).ToNot(ga.HaveOccurred())
6969
defer db.Close()
7070

7171
// Initialize data
7272
err = initializeBuckets(db)
73-
g.Expect(err).ToNot(HaveOccurred())
73+
g.Expect(err).ToNot(ga.HaveOccurred())
7474

7575
err = db.Update(func(t *bolt.Tx) error {
7676
doneTime := time.Now().Add(-10 * time.Minute)
@@ -95,10 +95,10 @@ func TestCleanupExpiredData(t *testing.T) {
9595

9696
return nil
9797
})
98-
g.Expect(err).ToNot(HaveOccurred())
98+
g.Expect(err).ToNot(ga.HaveOccurred())
9999

100100
err = cleanupExpiredData(time.Minute, db)
101-
g.Expect(err).ToNot(HaveOccurred())
101+
g.Expect(err).ToNot(ga.HaveOccurred())
102102

103103
actualGids := []string{}
104104
err = db.View(func(t *bolt.Tx) error {
@@ -108,29 +108,29 @@ func TestCleanupExpiredData(t *testing.T) {
108108
}
109109
return nil
110110
})
111-
g.Expect(err).ToNot(HaveOccurred())
112-
g.Expect(actualGids).To(Equal([]string{"gid0"}))
111+
g.Expect(err).ToNot(ga.HaveOccurred())
112+
g.Expect(actualGids).To(ga.Equal([]string{"gid0"}))
113113
})
114114
}
115115

116116
func TestCleanupGlobalWithGids(t *testing.T) {
117117
t.Run("nil bucket", func(t *testing.T) {
118-
g := NewWithT(t)
118+
g := ga.NewWithT(t)
119119
db, err := bolt.Open(path.Join(t.TempDir(), "./test.bolt"), 0666, &bolt.Options{Timeout: 1 * time.Second})
120-
g.Expect(err).ToNot(HaveOccurred())
120+
g.Expect(err).ToNot(ga.HaveOccurred())
121121
defer db.Close()
122122

123123
err = db.Update(func(t *bolt.Tx) error {
124124
cleanupGlobalWithGids(t, nil)
125125
return nil
126126
})
127-
g.Expect(err).ToNot(HaveOccurred())
127+
g.Expect(err).ToNot(ga.HaveOccurred())
128128
})
129129

130130
t.Run("normal test", func(t *testing.T) {
131-
g := NewWithT(t)
131+
g := ga.NewWithT(t)
132132
db, err := bolt.Open(path.Join(t.TempDir(), "./test.bolt"), 0666, &bolt.Options{Timeout: 1 * time.Second})
133-
g.Expect(err).ToNot(HaveOccurred())
133+
g.Expect(err).ToNot(ga.HaveOccurred())
134134
defer db.Close()
135135

136136
// Initialize data
@@ -151,7 +151,7 @@ func TestCleanupGlobalWithGids(t *testing.T) {
151151

152152
return nil
153153
})
154-
g.Expect(err).ToNot(HaveOccurred())
154+
g.Expect(err).ToNot(ga.HaveOccurred())
155155

156156
err = db.Update(func(t *bolt.Tx) error {
157157
cleanupGlobalWithGids(t, map[string]struct{}{
@@ -160,7 +160,7 @@ func TestCleanupGlobalWithGids(t *testing.T) {
160160
})
161161
return nil
162162
})
163-
g.Expect(err).ToNot(HaveOccurred())
163+
g.Expect(err).ToNot(ga.HaveOccurred())
164164

165165
actualGids := []string{}
166166
err = db.View(func(t *bolt.Tx) error {
@@ -170,29 +170,29 @@ func TestCleanupGlobalWithGids(t *testing.T) {
170170
}
171171
return nil
172172
})
173-
g.Expect(err).ToNot(HaveOccurred())
174-
g.Expect(actualGids).To(Equal([]string{"k3"}))
173+
g.Expect(err).ToNot(ga.HaveOccurred())
174+
g.Expect(actualGids).To(ga.Equal([]string{"k3"}))
175175
})
176176
}
177177

178178
func TestCleanupBranchWithGids(t *testing.T) {
179179
t.Run("nil bucket", func(t *testing.T) {
180-
g := NewWithT(t)
180+
g := ga.NewWithT(t)
181181
db, err := bolt.Open(path.Join(t.TempDir(), "./test.bolt"), 0666, &bolt.Options{Timeout: 1 * time.Second})
182-
g.Expect(err).ToNot(HaveOccurred())
182+
g.Expect(err).ToNot(ga.HaveOccurred())
183183
defer db.Close()
184184

185185
err = db.Update(func(t *bolt.Tx) error {
186186
cleanupBranchWithGids(t, nil)
187187
return nil
188188
})
189-
g.Expect(err).ToNot(HaveOccurred())
189+
g.Expect(err).ToNot(ga.HaveOccurred())
190190
})
191191

192192
t.Run("normal test", func(t *testing.T) {
193-
g := NewWithT(t)
193+
g := ga.NewWithT(t)
194194
db, err := bolt.Open(path.Join(t.TempDir(), "./test.bolt"), 0666, &bolt.Options{Timeout: 1 * time.Second})
195-
g.Expect(err).ToNot(HaveOccurred())
195+
g.Expect(err).ToNot(ga.HaveOccurred())
196196
defer db.Close()
197197

198198
// Initialize data
@@ -232,7 +232,7 @@ func TestCleanupBranchWithGids(t *testing.T) {
232232

233233
return nil
234234
})
235-
g.Expect(err).ToNot(HaveOccurred())
235+
g.Expect(err).ToNot(ga.HaveOccurred())
236236

237237
err = db.Update(func(t *bolt.Tx) error {
238238
cleanupBranchWithGids(t, map[string]struct{}{
@@ -241,7 +241,7 @@ func TestCleanupBranchWithGids(t *testing.T) {
241241
})
242242
return nil
243243
})
244-
g.Expect(err).ToNot(HaveOccurred())
244+
g.Expect(err).ToNot(ga.HaveOccurred())
245245

246246
actualKeys := []string{}
247247
err = db.View(func(t *bolt.Tx) error {
@@ -251,29 +251,29 @@ func TestCleanupBranchWithGids(t *testing.T) {
251251
}
252252
return nil
253253
})
254-
g.Expect(err).ToNot(HaveOccurred())
255-
g.Expect(actualKeys).To(Equal([]string{"a", "gid201", "z"}))
254+
g.Expect(err).ToNot(ga.HaveOccurred())
255+
g.Expect(actualKeys).To(ga.Equal([]string{"a", "gid201", "z"}))
256256
})
257257
}
258258

259259
func TestCleanupIndexWithGids(t *testing.T) {
260260
t.Run("nil bucket", func(t *testing.T) {
261-
g := NewWithT(t)
261+
g := ga.NewWithT(t)
262262
db, err := bolt.Open(path.Join(t.TempDir(), "./test.bolt"), 0666, &bolt.Options{Timeout: 1 * time.Second})
263-
g.Expect(err).ToNot(HaveOccurred())
263+
g.Expect(err).ToNot(ga.HaveOccurred())
264264
defer db.Close()
265265

266266
err = db.Update(func(t *bolt.Tx) error {
267267
cleanupIndexWithGids(t, nil)
268268
return nil
269269
})
270-
g.Expect(err).ToNot(HaveOccurred())
270+
g.Expect(err).ToNot(ga.HaveOccurred())
271271
})
272272

273273
t.Run("normal test", func(t *testing.T) {
274-
g := NewWithT(t)
274+
g := ga.NewWithT(t)
275275
db, err := bolt.Open(path.Join(t.TempDir(), "./test.bolt"), 0666, &bolt.Options{Timeout: 1 * time.Second})
276-
g.Expect(err).ToNot(HaveOccurred())
276+
g.Expect(err).ToNot(ga.HaveOccurred())
277277
defer db.Close()
278278

279279
// Initialize data
@@ -313,7 +313,7 @@ func TestCleanupIndexWithGids(t *testing.T) {
313313

314314
return nil
315315
})
316-
g.Expect(err).ToNot(HaveOccurred())
316+
g.Expect(err).ToNot(ga.HaveOccurred())
317317

318318
err = db.Update(func(t *bolt.Tx) error {
319319
cleanupIndexWithGids(t, map[string]struct{}{
@@ -322,7 +322,7 @@ func TestCleanupIndexWithGids(t *testing.T) {
322322
})
323323
return nil
324324
})
325-
g.Expect(err).ToNot(HaveOccurred())
325+
g.Expect(err).ToNot(ga.HaveOccurred())
326326

327327
actualKeys := []string{}
328328
err = db.View(func(t *bolt.Tx) error {
@@ -332,7 +332,7 @@ func TestCleanupIndexWithGids(t *testing.T) {
332332
}
333333
return nil
334334
})
335-
g.Expect(err).ToNot(HaveOccurred())
336-
g.Expect(actualKeys).To(Equal([]string{"3-gid2", "a", "z"}))
335+
g.Expect(err).ToNot(ga.HaveOccurred())
336+
g.Expect(actualKeys).To(ga.Equal([]string{"3-gid2", "a", "z"}))
337337
})
338338
}

dtmsvr/storage/sql/sql.go

+14-9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
package sql
99

1010
import (
11+
"database/sql"
12+
"errors"
1113
"fmt"
1214
"math"
1315
"time"
@@ -159,23 +161,26 @@ func (s *Store) LockOneGlobalTrans(expireIn time.Duration) *storage.TransGlobalS
159161
db := dbGet()
160162
owner := shortuuid.New()
161163
nextCronTime := getTimeStr(int64(expireIn / time.Second))
162-
where := map[string]string{
163-
dtmimp.DBTypeMysql: fmt.Sprintf(`next_cron_time < '%s' and status in ('prepared', 'aborting', 'submitted') limit 1`, nextCronTime),
164-
dtmimp.DBTypePostgres: fmt.Sprintf(`id in (select id from trans_global where next_cron_time < '%s' and status in ('prepared', 'aborting', 'submitted') limit 1 )`, nextCronTime),
164+
where := fmt.Sprintf(`next_cron_time < '%s' and status in ('prepared', 'aborting', 'submitted')`, nextCronTime)
165+
166+
order := map[string]string{
167+
dtmimp.DBTypeMysql: `order by rand()`,
168+
dtmimp.DBTypePostgres: `order by random()`,
165169
}[conf.Store.Driver]
166170

167-
ssql := fmt.Sprintf(`select count(1) from trans_global where %s`, where)
168-
var cnt int64
169-
err := db.ToSQLDB().QueryRow(ssql).Scan(&cnt)
170-
dtmimp.PanicIf(err != nil, err)
171-
if cnt == 0 {
171+
ssql := fmt.Sprintf(`select id from trans_global where %s %s limit 1`, where, order)
172+
var id int64
173+
err := db.ToSQLDB().QueryRow(ssql).Scan(&id)
174+
if errors.Is(err, sql.ErrNoRows) {
172175
return nil
173176
}
177+
dtmimp.PanicIf(err != nil, err)
174178

175-
sql := fmt.Sprintf(`UPDATE trans_global SET update_time='%s',next_cron_time='%s', owner='%s' WHERE %s`,
179+
sql := fmt.Sprintf(`UPDATE trans_global SET update_time='%s',next_cron_time='%s', owner='%s' WHERE id=%d and %s`,
176180
getTimeStr(0),
177181
getTimeStr(conf.RetryInterval),
178182
owner,
183+
id,
179184
where)
180185
affected, err := dtmimp.DBExec(conf.Store.Driver, db.ToSQLDB(), sql)
181186

dtmsvr/trans_status.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,15 @@ func (t *TransGlobal) execBranch(ctx context.Context, branch *TransBranch, branc
262262
func (t *TransGlobal) getNextCronInterval(ctype cronType) int64 {
263263
if ctype == cronBackoff {
264264
return t.NextCronInterval * 2
265-
} else if ctype == cronKeep {
265+
}
266+
if ctype == cronKeep {
266267
return t.NextCronInterval
267-
} else if t.RetryInterval != 0 {
268+
}
269+
if t.RetryInterval != 0 {
268270
return t.RetryInterval
269-
} else if t.TimeoutToFail > 0 && t.TimeoutToFail < conf.RetryInterval {
271+
}
272+
if t.TimeoutToFail > 0 && t.TimeoutToFail < conf.RetryInterval {
270273
return t.TimeoutToFail
271-
} else {
272-
return conf.RetryInterval
273274
}
275+
return conf.RetryInterval
274276
}

0 commit comments

Comments
 (0)