@@ -21,6 +21,7 @@ import (
2121 "log"
2222 "net/url"
2323 "strings"
24+ "sync"
2425 "time"
2526
2627 apiv1 "github.com/google/cloud-android-orchestration/api/v1"
@@ -53,8 +54,9 @@ const uaMountTarget = "/var/lib/cuttlefish-common/userartifacts"
5354
5455// Docker implementation of the instance manager.
5556type DockerInstanceManager struct {
56- Config Config
57- Client * client.Client
57+ Config Config
58+ Client * client.Client
59+ mutexes sync.Map
5860}
5961
6062type OPType string
@@ -83,6 +85,9 @@ func (m *DockerInstanceManager) CreateHost(zone string, _ *apiv1.CreateHostReque
8385 if zone != "local" {
8486 return nil , errors .NewBadRequestError ("Invalid zone. It should be 'local'." , nil )
8587 }
88+ mu := m .getRWMutex (user )
89+ mu .RLock ()
90+ defer mu .RUnlock ()
8691 ctx := context .TODO ()
8792 if err := m .downloadDockerImageIfNeeded (ctx ); err != nil {
8893 return nil , fmt .Errorf ("failed to retrieve docker image name: %w" , err )
@@ -423,6 +428,15 @@ func (m *DockerInstanceManager) deleteDockerVolumeIfNeeded(ctx context.Context,
423428 if len (listRes ) > 0 {
424429 return nil
425430 }
431+
432+ mu := m .getRWMutex (user )
433+ if locked := mu .TryLock (); ! locked {
434+ // If it can't acquire lock on this mutex, there's ongoing host
435+ // creation with this volume or deletion of this volume. For these
436+ // cases, it doesn't need to delete docker volume here.
437+ return nil
438+ }
439+ defer mu .Unlock ()
426440 listOpts := volume.ListOptions {Filters : dockerFilter (user )}
427441 volumeListRes , err := m .Client .VolumeList (ctx , listOpts )
428442 if err != nil {
@@ -435,3 +449,8 @@ func (m *DockerInstanceManager) deleteDockerVolumeIfNeeded(ctx context.Context,
435449 }
436450 return nil
437451}
452+
453+ func (m * DockerInstanceManager ) getRWMutex (user accounts.User ) * sync.RWMutex {
454+ mu , _ := m .mutexes .LoadOrStore (user .Username (), & sync.RWMutex {})
455+ return mu .(* sync.RWMutex )
456+ }
0 commit comments