@@ -16,10 +16,12 @@ package dsess
16
16
17
17
import (
18
18
"context"
19
+ "errors"
19
20
"io"
20
21
"math"
21
22
"strings"
22
23
"sync"
24
+ "time"
23
25
24
26
"github.com/dolthub/go-mysql-server/sql"
25
27
gmstypes "github.com/dolthub/go-mysql-server/sql/types"
@@ -48,6 +50,8 @@ type AutoIncrementTracker struct {
48
50
sequences * sync.Map // map[string]uint64
49
51
mm * mutexmap.MutexMap
50
52
lockMode LockMode
53
+ init chan struct {}
54
+ initErr error
51
55
}
52
56
53
57
var _ globalstate.AutoIncrementTracker = & AutoIncrementTracker {}
@@ -61,8 +65,9 @@ func NewAutoIncrementTracker(ctx context.Context, dbName string, roots ...doltdb
61
65
dbName : dbName ,
62
66
sequences : & sync.Map {},
63
67
mm : mutexmap .NewMutexMap (),
68
+ init : make (chan struct {}),
64
69
}
65
- ait .InitWithRoots (ctx , roots ... )
70
+ ait .runInitWithRootsAsync (ctx , roots ... )
66
71
return & ait , nil
67
72
}
68
73
@@ -76,13 +81,22 @@ func loadAutoIncValue(sequences *sync.Map, tableName string) uint64 {
76
81
}
77
82
78
83
// Current returns the next value to be generated in the auto increment sequence for the table named
79
- func (a * AutoIncrementTracker ) Current (tableName string ) uint64 {
80
- return loadAutoIncValue (a .sequences , tableName )
84
+ func (a * AutoIncrementTracker ) Current (tableName string ) (uint64 , error ) {
85
+ err := a .waitForInit ()
86
+ if err != nil {
87
+ return 0 , err
88
+ }
89
+ return loadAutoIncValue (a .sequences , tableName ), nil
81
90
}
82
91
83
92
// Next returns the next auto increment value for the table named using the provided value from an insert (which may
84
93
// be null or 0, in which case it will be generated from the sequence).
85
94
func (a * AutoIncrementTracker ) Next (tbl string , insertVal interface {}) (uint64 , error ) {
95
+ err := a .waitForInit ()
96
+ if err != nil {
97
+ return 0 , err
98
+ }
99
+
86
100
tbl = strings .ToLower (tbl )
87
101
88
102
given , err := CoerceAutoIncrementValue (insertVal )
@@ -113,6 +127,10 @@ func (a *AutoIncrementTracker) Next(tbl string, insertVal interface{}) (uint64,
113
127
}
114
128
115
129
func (a * AutoIncrementTracker ) CoerceAutoIncrementValue (val interface {}) (uint64 , error ) {
130
+ err := a .waitForInit ()
131
+ if err != nil {
132
+ return 0 , err
133
+ }
116
134
return CoerceAutoIncrementValue (val )
117
135
}
118
136
@@ -140,6 +158,11 @@ func CoerceAutoIncrementValue(val interface{}) (uint64, error) {
140
158
// table. Otherwise, the update is silently disregarded. So far this matches the MySQL behavior, but Dolt uses the
141
159
// maximum value for this table across all branches.
142
160
func (a * AutoIncrementTracker ) Set (ctx * sql.Context , tableName string , table * doltdb.Table , ws ref.WorkingSetRef , newAutoIncVal uint64 ) (* doltdb.Table , error ) {
161
+ err := a .waitForInit ()
162
+ if err != nil {
163
+ return nil , err
164
+ }
165
+
143
166
tableName = strings .ToLower (tableName )
144
167
145
168
release := a .mm .Lock (tableName )
@@ -338,16 +361,27 @@ func getMaxIndexValue(ctx context.Context, indexData durable.Index) (uint64, err
338
361
}
339
362
340
363
// AddNewTable initializes a new table with an auto increment column to the tracker, as necessary
341
- func (a * AutoIncrementTracker ) AddNewTable (tableName string ) {
364
+ func (a * AutoIncrementTracker ) AddNewTable (tableName string ) error {
365
+ err := a .waitForInit ()
366
+ if err != nil {
367
+ return err
368
+ }
369
+
342
370
tableName = strings .ToLower (tableName )
343
371
// only initialize the sequence for this table if no other branch has such a table
344
372
a .sequences .LoadOrStore (tableName , uint64 (1 ))
373
+ return nil
345
374
}
346
375
347
376
// DropTable drops the table with the name given.
348
377
// To establish the new auto increment value, callers must also pass all other working sets in scope that may include
349
378
// a table with the same name, omitting the working set that just deleted the table named.
350
379
func (a * AutoIncrementTracker ) DropTable (ctx * sql.Context , tableName string , wses ... * doltdb.WorkingSet ) error {
380
+ err := a .waitForInit ()
381
+ if err != nil {
382
+ return err
383
+ }
384
+
351
385
tableName = strings .ToLower (tableName )
352
386
353
387
release := a .mm .Lock (tableName )
@@ -389,6 +423,11 @@ func (a *AutoIncrementTracker) DropTable(ctx *sql.Context, tableName string, wse
389
423
}
390
424
391
425
func (a * AutoIncrementTracker ) AcquireTableLock (ctx * sql.Context , tableName string ) (func (), error ) {
426
+ err := a .waitForInit ()
427
+ if err != nil {
428
+ return nil , err
429
+ }
430
+
392
431
_ , i , _ := sql .SystemVariables .GetGlobal ("innodb_autoinc_lock_mode" )
393
432
lockMode := LockMode (i .(int64 ))
394
433
if lockMode == LockMode_Interleaved {
@@ -398,7 +437,23 @@ func (a *AutoIncrementTracker) AcquireTableLock(ctx *sql.Context, tableName stri
398
437
return a .mm .Lock (tableName ), nil
399
438
}
400
439
401
- func (a * AutoIncrementTracker ) InitWithRoots (ctx context.Context , roots ... doltdb.Rootish ) error {
440
+ func (a * AutoIncrementTracker ) waitForInit () error {
441
+ select {
442
+ case <- a .init :
443
+ return a .initErr
444
+ case <- time .After (5 * time .Minute ):
445
+ return errors .New ("failed to initialize autoincrement tracker" )
446
+ }
447
+ }
448
+
449
+ func (a * AutoIncrementTracker ) runInitWithRootsAsync (ctx context.Context , roots ... doltdb.Rootish ) {
450
+ go func () {
451
+ defer close (a .init )
452
+ a .initErr = a .initWithRoots (ctx , roots ... )
453
+ }()
454
+ }
455
+
456
+ func (a * AutoIncrementTracker ) initWithRoots (ctx context.Context , roots ... doltdb.Rootish ) error {
402
457
eg , egCtx := errgroup .WithContext (ctx )
403
458
eg .SetLimit (128 )
404
459
@@ -435,3 +490,13 @@ func (a *AutoIncrementTracker) InitWithRoots(ctx context.Context, roots ...doltd
435
490
436
491
return eg .Wait ()
437
492
}
493
+
494
+ func (a * AutoIncrementTracker ) InitWithRoots (ctx context.Context , roots ... doltdb.Rootish ) error {
495
+ err := a .waitForInit ()
496
+ if err != nil {
497
+ return err
498
+ }
499
+ a .init = make (chan struct {})
500
+ a .runInitWithRootsAsync (ctx , roots ... )
501
+ return a .waitForInit ()
502
+ }
0 commit comments