From f0f2220abb592d46a50b4f3d1010bf9a1e4739d2 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Thu, 25 May 2017 11:01:25 -0400 Subject: [PATCH] add mutexes to remote.State --- state/remote/state.go | 21 +++++++++++++++++++++ state/remote/state_test.go | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/state/remote/state.go b/state/remote/state.go index c87416705..dccbab18a 100644 --- a/state/remote/state.go +++ b/state/remote/state.go @@ -2,6 +2,7 @@ package remote import ( "bytes" + "sync" "github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/terraform" @@ -12,6 +13,8 @@ import ( // local caching so every persist will go to the remote storage and local // writes will go to memory. type State struct { + mu sync.Mutex + Client Client state, readState *terraform.State @@ -19,17 +22,26 @@ type State struct { // StateReader impl. func (s *State) State() *terraform.State { + s.mu.Lock() + defer s.mu.Unlock() + return s.state.DeepCopy() } // StateWriter impl. func (s *State) WriteState(state *terraform.State) error { + s.mu.Lock() + defer s.mu.Unlock() + s.state = state return nil } // StateRefresher impl. func (s *State) RefreshState() error { + s.mu.Lock() + defer s.mu.Unlock() + payload, err := s.Client.Get() if err != nil { return err @@ -52,6 +64,9 @@ func (s *State) RefreshState() error { // StatePersister impl. func (s *State) PersistState() error { + s.mu.Lock() + defer s.mu.Unlock() + s.state.IncrementSerialMaybe(s.readState) var buf bytes.Buffer @@ -64,6 +79,9 @@ func (s *State) PersistState() error { // Lock calls the Client's Lock method if it's implemented. func (s *State) Lock(info *state.LockInfo) (string, error) { + s.mu.Lock() + defer s.mu.Unlock() + if c, ok := s.Client.(ClientLocker); ok { return c.Lock(info) } @@ -72,6 +90,9 @@ func (s *State) Lock(info *state.LockInfo) (string, error) { // Unlock calls the Client's Unlock method if it's implemented. func (s *State) Unlock(id string) error { + s.mu.Lock() + defer s.mu.Unlock() + if c, ok := s.Client.(ClientLocker); ok { return c.Unlock(id) } diff --git a/state/remote/state_test.go b/state/remote/state_test.go index 90a60e9c4..26a031b7e 100644 --- a/state/remote/state_test.go +++ b/state/remote/state_test.go @@ -1,6 +1,7 @@ package remote import ( + "sync" "testing" "github.com/hashicorp/terraform/state" @@ -13,3 +14,24 @@ func TestState_impl(t *testing.T) { var _ state.StateRefresher = new(State) var _ state.Locker = new(State) } + +func TestStateRace(t *testing.T) { + s := &State{ + Client: nilClient{}, + } + + current := state.TestStateInitial() + + var wg sync.WaitGroup + + for i := 0; i < 100; i++ { + wg.Add(1) + go func() { + defer wg.Done() + s.WriteState(current) + s.PersistState() + s.RefreshState() + }() + } + wg.Wait() +}