@@ -27,7 +27,6 @@ const idleCheckDuration = 5 * time.Minute
27
27
type baseCloning struct {
28
28
cloning
29
29
30
- // TODO(akartasov): Fix data race.
31
30
cloneMutex sync.RWMutex
32
31
clones map [string ]* CloneWrapper
33
32
instanceStatus * models.InstanceStatus
@@ -91,10 +90,10 @@ func (c *baseCloning) CreateClone(clone *models.Clone) error {
91
90
92
91
w := NewCloneWrapper (clone )
93
92
94
- clone . Status = & models.Status {
93
+ c . updateStatus ( w . clone , models.Status {
95
94
Code : models .StatusCreating ,
96
95
Message : models .CloneMessageCreating ,
97
- }
96
+ })
98
97
99
98
w .timeCreatedAt = time .Now ()
100
99
clone .CreatedAt = util .FormatTime (w .timeCreatedAt )
@@ -119,10 +118,10 @@ func (c *baseCloning) CreateClone(clone *models.Clone) error {
119
118
session , err := c .provision .StartSession (w .username , w .password , snapshotID )
120
119
if err != nil {
121
120
// TODO(anatoly): Empty room case.
122
- clone . Status = & models.Status {
121
+ c . updateStatus ( w . clone , models.Status {
123
122
Code : models .StatusFatal ,
124
123
Message : models .CloneMessageFatal ,
125
- }
124
+ })
126
125
127
126
log .Errf ("Failed to start session: %+v." , err )
128
127
@@ -133,10 +132,10 @@ func (c *baseCloning) CreateClone(clone *models.Clone) error {
133
132
134
133
w .timeStartedAt = time .Now ()
135
134
136
- clone . Status = & models.Status {
135
+ c . updateStatus ( w . clone , models.Status {
137
136
Code : models .StatusOK ,
138
137
Message : models .CloneMessageOK ,
139
- }
138
+ })
140
139
141
140
clone .DB .Port = strconv .FormatUint (uint64 (session .Port ), 10 )
142
141
@@ -169,30 +168,28 @@ func (c *baseCloning) DestroyClone(id string) error {
169
168
return errors .New ("clone is protected" )
170
169
}
171
170
172
- w .clone . Status = & models.Status {
171
+ c . updateStatus ( w .clone , models.Status {
173
172
Code : models .StatusDeleting ,
174
173
Message : models .CloneMessageDeleting ,
175
- }
174
+ })
176
175
177
176
if w .session == nil {
178
177
return errors .New ("clone is not started yet" )
179
178
}
180
179
181
180
go func () {
182
181
if err := c .provision .StopSession (w .session ); err != nil {
183
- w .clone . Status = & models.Status {
182
+ c . updateStatus ( w .clone , models.Status {
184
183
Code : models .StatusFatal ,
185
184
Message : models .CloneMessageFatal ,
186
- }
185
+ })
187
186
188
187
log .Errf ("Failed to delete clone: %+v." , err )
189
188
190
189
return
191
190
}
192
191
193
- c .cloneMutex .Lock ()
194
- delete (c .clones , w .clone .ID )
195
- c .cloneMutex .Unlock ()
192
+ c .deleteClone (w .clone .ID )
196
193
}()
197
194
198
195
return nil
@@ -274,10 +271,10 @@ func (c *baseCloning) ResetClone(id string) error {
274
271
return errors .New ("clone not found" )
275
272
}
276
273
277
- w .clone . Status = & models.Status {
274
+ c . updateStatus ( w .clone , models.Status {
278
275
Code : models .StatusResetting ,
279
276
Message : models .CloneMessageResetting ,
280
- }
277
+ })
281
278
282
279
if w .session == nil {
283
280
return errors .New ("clone is not started yet" )
@@ -291,20 +288,20 @@ func (c *baseCloning) ResetClone(id string) error {
291
288
292
289
err := c .provision .ResetSession (w .session , snapshotID )
293
290
if err != nil {
294
- w .clone . Status = & models.Status {
291
+ c . updateStatus ( w .clone , models.Status {
295
292
Code : models .StatusFatal ,
296
293
Message : models .CloneMessageFatal ,
297
- }
294
+ })
298
295
299
296
log .Errf ("Failed to reset session: %+v." , err )
300
297
301
298
return
302
299
}
303
300
304
- w .clone . Status = & models.Status {
301
+ c . updateStatus ( w .clone , models.Status {
305
302
Code : models .StatusOK ,
306
303
Message : models .CloneMessageOK ,
307
- }
304
+ })
308
305
}()
309
306
310
307
return nil
@@ -337,10 +334,13 @@ func (c *baseCloning) GetSnapshots() ([]*models.Snapshot, error) {
337
334
338
335
// GetClones returns all clones.
339
336
func (c * baseCloning ) GetClones () []* models.Clone {
340
- clones := make ([]* models.Clone , 0 , len (c .clones ))
337
+ clones := make ([]* models.Clone , 0 , c .lenClones ())
338
+
339
+ c .cloneMutex .RLock ()
341
340
for _ , clone := range c .clones {
342
341
clones = append (clones , clone .clone )
343
342
}
343
+ c .cloneMutex .RUnlock ()
344
344
345
345
return clones
346
346
}
@@ -361,20 +361,47 @@ func (c *baseCloning) setWrapper(id string, wrapper *CloneWrapper) {
361
361
c .cloneMutex .Unlock ()
362
362
}
363
363
364
+ // updateStatus updates the clone status.
365
+ func (c * baseCloning ) updateStatus (clone * models.Clone , status models.Status ) {
366
+ c .cloneMutex .Lock ()
367
+ clone .Status = & status
368
+ c .cloneMutex .Unlock ()
369
+ }
370
+
371
+ // deleteClone removes the clone by ID.
372
+ func (c * baseCloning ) deleteClone (cloneID string ) {
373
+ c .cloneMutex .Lock ()
374
+ delete (c .clones , cloneID )
375
+ c .cloneMutex .Unlock ()
376
+ }
377
+
378
+ // lenClones returns the number of clones.
379
+ func (c * baseCloning ) lenClones () int {
380
+ c .cloneMutex .RLock ()
381
+ lenClones := len (c .clones )
382
+ c .cloneMutex .RUnlock ()
383
+
384
+ return lenClones
385
+ }
386
+
364
387
func (c * baseCloning ) getExpectedCloningTime () float64 {
365
- if len (c .clones ) == 0 {
388
+ lenClones := c .lenClones ()
389
+
390
+ if lenClones == 0 {
366
391
return 0
367
392
}
368
393
369
394
sum := 0.0
370
395
396
+ c .cloneMutex .RLock ()
371
397
for _ , cloneWrapper := range c .clones {
372
398
if cloneWrapper .clone .Metadata != nil {
373
399
sum += cloneWrapper .clone .Metadata .CloningTime
374
400
}
375
401
}
402
+ c .cloneMutex .RUnlock ()
376
403
377
- return sum / float64 (len ( c . clones ) )
404
+ return sum / float64 (lenClones )
378
405
}
379
406
380
407
func (c * baseCloning ) fetchSnapshots () error {
0 commit comments