Skip to content

Commit b6624b7

Browse files
jascott1technosophos
authored andcommitted
fix(tiller): remove locking system from storage and rely on backend controls
Tiller currently hangs indefinitely when deadlocks arise from certain concurrent operations. This commit removes the nested mutex locking system from pkg/Storage and relies on resource contention controls in k8s. Closes #2560
1 parent aa54325 commit b6624b7

File tree

6 files changed

+3
-105
lines changed

6 files changed

+3
-105
lines changed

pkg/storage/driver/cfgmaps.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func (cfgmaps *ConfigMaps) Create(key string, rls *rspb.Release) error {
173173
// push the configmap object out into the kubiverse
174174
if _, err := cfgmaps.impl.Create(obj); err != nil {
175175
if apierrors.IsAlreadyExists(err) {
176-
return ErrReleaseExists(rls.Name)
176+
return ErrReleaseExists(key)
177177
}
178178

179179
cfgmaps.Log("create: failed to create: %s", err)

pkg/storage/storage.go

Lines changed: 2 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package storage // import "k8s.io/helm/pkg/storage"
1818

1919
import (
2020
"fmt"
21-
"sync"
2221

2322
rspb "k8s.io/helm/pkg/proto/hapi/release"
2423
relutil "k8s.io/helm/pkg/releaseutil"
@@ -28,12 +27,6 @@ import (
2827
// Storage represents a storage engine for a Release.
2928
type Storage struct {
3029
driver.Driver
31-
32-
// releaseLocks are for locking releases to make sure that only one operation at a time is executed on each release
33-
releaseLocks map[string]*sync.Mutex
34-
// releaseLocksLock is a mutex for accessing releaseLocks
35-
releaseLocksLock *sync.Mutex
36-
3730
Log func(string, ...interface{})
3831
}
3932

@@ -157,53 +150,6 @@ func (s *Storage) Last(name string) (*rspb.Release, error) {
157150
return h[0], nil
158151
}
159152

160-
// LockRelease gains a mutually exclusive access to a release via a mutex.
161-
func (s *Storage) LockRelease(name string) error {
162-
s.Log("locking release %s", name)
163-
s.releaseLocksLock.Lock()
164-
defer s.releaseLocksLock.Unlock()
165-
166-
var lock *sync.Mutex
167-
lock, exists := s.releaseLocks[name]
168-
169-
if !exists {
170-
releases, err := s.ListReleases()
171-
if err != nil {
172-
return err
173-
}
174-
175-
found := false
176-
for _, release := range releases {
177-
if release.Name == name {
178-
found = true
179-
}
180-
}
181-
if !found {
182-
return fmt.Errorf("Unable to lock release %q: release not found", name)
183-
}
184-
185-
lock = &sync.Mutex{}
186-
s.releaseLocks[name] = lock
187-
}
188-
lock.Lock()
189-
return nil
190-
}
191-
192-
// UnlockRelease releases a mutually exclusive access to a release.
193-
// If release doesn't exist or wasn't previously locked - the unlock will pass
194-
func (s *Storage) UnlockRelease(name string) {
195-
s.Log("unlocking release %s", name)
196-
s.releaseLocksLock.Lock()
197-
defer s.releaseLocksLock.Unlock()
198-
199-
var lock *sync.Mutex
200-
lock, exists := s.releaseLocks[name]
201-
if !exists {
202-
return
203-
}
204-
lock.Unlock()
205-
}
206-
207153
// makeKey concatenates a release name and version into
208154
// a string with format ```<release_name>#v<version>```.
209155
// This key is used to uniquely identify storage objects.
@@ -219,9 +165,7 @@ func Init(d driver.Driver) *Storage {
219165
d = driver.NewMemory()
220166
}
221167
return &Storage{
222-
Driver: d,
223-
releaseLocks: make(map[string]*sync.Mutex),
224-
releaseLocksLock: &sync.Mutex{},
225-
Log: func(_ string, _ ...interface{}) {},
168+
Driver: d,
169+
Log: func(_ string, _ ...interface{}) {},
226170
}
227171
}

pkg/storage/storage_test.go

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -272,31 +272,3 @@ func assertErrNil(eh func(args ...interface{}), err error, message string) {
272272
eh(fmt.Sprintf("%s: %q", message, err))
273273
}
274274
}
275-
276-
func TestReleaseLocksNotExist(t *testing.T) {
277-
s := Init(driver.NewMemory())
278-
279-
err := s.LockRelease("no-such-release")
280-
281-
if err == nil {
282-
t.Errorf("Exptected error when trying to lock non-existing release, got nil")
283-
}
284-
}
285-
286-
func TestReleaseLocks(t *testing.T) {
287-
s := Init(driver.NewMemory())
288-
289-
releaseName := "angry-beaver"
290-
rls := ReleaseTestData{
291-
Name: releaseName,
292-
Version: 1,
293-
}.ToRelease()
294-
295-
s.Create(rls)
296-
297-
err := s.LockRelease(releaseName)
298-
if err != nil {
299-
t.Errorf("Exptected nil err when locking existing release")
300-
}
301-
s.UnlockRelease(releaseName)
302-
}

pkg/tiller/release_rollback.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,6 @@ import (
2929

3030
// RollbackRelease rolls back to a previous version of the given release.
3131
func (s *ReleaseServer) RollbackRelease(c ctx.Context, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) {
32-
err := s.env.Releases.LockRelease(req.Name)
33-
if err != nil {
34-
return nil, err
35-
}
36-
defer s.env.Releases.UnlockRelease(req.Name)
37-
3832
s.Log("preparing rollback of %s", req.Name)
3933
currentRelease, targetRelease, err := s.prepareRollback(req)
4034
if err != nil {

pkg/tiller/release_uninstall.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,6 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
4040
return nil, fmt.Errorf("release name %q exceeds max length of %d", req.Name, releaseNameMaxLen)
4141
}
4242

43-
err := s.env.Releases.LockRelease(req.Name)
44-
if err != nil {
45-
return nil, err
46-
}
47-
defer s.env.Releases.UnlockRelease(req.Name)
48-
4943
rels, err := s.env.Releases.History(req.Name)
5044
if err != nil {
5145
s.Log("uninstall: Release not loaded: %s", req.Name)

pkg/tiller/release_update.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@ import (
3030

3131
// UpdateRelease takes an existing release and new information, and upgrades the release.
3232
func (s *ReleaseServer) UpdateRelease(c ctx.Context, req *services.UpdateReleaseRequest) (*services.UpdateReleaseResponse, error) {
33-
err := s.env.Releases.LockRelease(req.Name)
34-
if err != nil {
35-
return nil, err
36-
}
37-
defer s.env.Releases.UnlockRelease(req.Name)
38-
3933
s.Log("preparing update for %s", req.Name)
4034
currentRelease, updatedRelease, err := s.prepareUpdate(req)
4135
if err != nil {

0 commit comments

Comments
 (0)