9
9
"fmt"
10
10
"strconv"
11
11
"strings"
12
+ "sync"
12
13
"time"
13
14
14
15
"gitlab.com/postgres-ai/database-lab/pkg/log"
@@ -27,6 +28,7 @@ type baseCloning struct {
27
28
cloning
28
29
29
30
// TODO(akartasov): Fix data race.
31
+ cloneMutex sync.RWMutex
30
32
clones map [string ]* CloneWrapper
31
33
instanceStatus * models.InstanceStatus
32
34
snapshots []* models.Snapshot
@@ -67,7 +69,7 @@ func (c *baseCloning) CreateClone(clone *models.Clone) error {
67
69
// TODO(akartasov): Separate validation rules.
68
70
clone .ID = strings .TrimSpace (clone .ID )
69
71
70
- if _ , ok := c .clones [ clone .ID ] ; ok {
72
+ if _ , ok := c .findWrapper ( clone .ID ) ; ok {
71
73
return errors .New ("clone with such ID already exists" )
72
74
}
73
75
@@ -88,7 +90,6 @@ func (c *baseCloning) CreateClone(clone *models.Clone) error {
88
90
}
89
91
90
92
w := NewCloneWrapper (clone )
91
- c .clones [clone .ID ] = w
92
93
93
94
clone .Status = & models.Status {
94
95
Code : models .StatusCreating ,
@@ -153,11 +154,13 @@ func (c *baseCloning) CreateClone(clone *models.Clone) error {
153
154
}
154
155
}()
155
156
157
+ c .setWrapper (clone .ID , w )
158
+
156
159
return nil
157
160
}
158
161
159
162
func (c * baseCloning ) DestroyClone (id string ) error {
160
- w , ok := c .clones [ id ]
163
+ w , ok := c .findWrapper ( id )
161
164
if ! ok {
162
165
return errors .New ("clone not found" )
163
166
}
@@ -187,14 +190,16 @@ func (c *baseCloning) DestroyClone(id string) error {
187
190
return
188
191
}
189
192
193
+ c .cloneMutex .Lock ()
190
194
delete (c .clones , w .clone .ID )
195
+ c .cloneMutex .Unlock ()
191
196
}()
192
197
193
198
return nil
194
199
}
195
200
196
201
func (c * baseCloning ) GetClone (id string ) (* models.Clone , error ) {
197
- w , ok := c .clones [ id ]
202
+ w , ok := c .findWrapper ( id )
198
203
if ! ok {
199
204
return nil , errors .New ("clone not found" )
200
205
}
@@ -249,20 +254,22 @@ func (c *baseCloning) UpdateClone(id string, patch *models.Clone) error {
249
254
return errors .New ("CreatedAt cannot be changed" )
250
255
}
251
256
252
- w , ok := c .clones [ id ]
257
+ w , ok := c .findWrapper ( id )
253
258
if ! ok {
254
259
return errors .New ("clone not found" )
255
260
}
256
261
257
262
// Set fields.
258
263
264
+ c .cloneMutex .Lock ()
259
265
w .clone .Protected = patch .Protected
266
+ c .cloneMutex .Unlock ()
260
267
261
268
return nil
262
269
}
263
270
264
271
func (c * baseCloning ) ResetClone (id string ) error {
265
- w , ok := c .clones [ id ]
272
+ w , ok := c .findWrapper ( id )
266
273
if ! ok {
267
274
return errors .New ("clone not found" )
268
275
}
@@ -328,15 +335,32 @@ func (c *baseCloning) GetSnapshots() ([]*models.Snapshot, error) {
328
335
return c .snapshots , nil
329
336
}
330
337
338
+ // GetClones returns all clones.
331
339
func (c * baseCloning ) GetClones () []* models.Clone {
332
- clones := make ([]* models.Clone , 0 )
340
+ clones := make ([]* models.Clone , 0 , len ( c . clones ) )
333
341
for _ , clone := range c .clones {
334
342
clones = append (clones , clone .clone )
335
343
}
336
344
337
345
return clones
338
346
}
339
347
348
+ // findWrapper retrieves a clone findWrapper by id.
349
+ func (c * baseCloning ) findWrapper (id string ) (* CloneWrapper , bool ) {
350
+ c .cloneMutex .RLock ()
351
+ w , ok := c .clones [id ]
352
+ c .cloneMutex .RUnlock ()
353
+
354
+ return w , ok
355
+ }
356
+
357
+ // setWrapper adds a clone wrapper to the map of clones.
358
+ func (c * baseCloning ) setWrapper (id string , wrapper * CloneWrapper ) {
359
+ c .cloneMutex .Lock ()
360
+ c .clones [id ] = wrapper
361
+ c .cloneMutex .Unlock ()
362
+ }
363
+
340
364
func (c * baseCloning ) getExpectedCloningTime () float64 {
341
365
if len (c .clones ) == 0 {
342
366
return 0
@@ -432,6 +456,11 @@ func (c *baseCloning) isIdleClone(wrapper *CloneWrapper) (bool, error) {
432
456
433
457
session := wrapper .session
434
458
459
+ // TODO(akartasov): Remove wrappers without session.
460
+ if session == nil {
461
+ return false , errors .New ("failed to get clone session" )
462
+ }
463
+
435
464
lastSessionActivity , err := c .provision .LastSessionActivity (session , idleDuration )
436
465
if err != nil {
437
466
if err == pglog .ErrNotFound {
0 commit comments