@ -19,6 +19,7 @@ package storage // import "k8s.io/helm/pkg/storage"
import (
"fmt"
"log"
"sync"
rspb "k8s.io/helm/pkg/proto/hapi/release"
relutil "k8s.io/helm/pkg/releaseutil"
@ -28,6 +29,11 @@ import (
// Storage represents a storage engine for a Release.
type Storage struct {
driver . Driver
// releaseLocks are for locking releases to make sure that only one operation at a time is executed on each release
releaseLocks map [ string ] * sync . Mutex
// releaseLocksLock is a mutex for accessing releaseLocks
releaseLocksLock * sync . Mutex
}
// Get retrieves the release from storage. An error is returned
@ -153,6 +159,51 @@ func (s *Storage) Last(name string) (*rspb.Release, error) {
return h [ 0 ] , nil
}
// LockRelease gains a mutually exclusive access to a release via a mutex.
func ( s * Storage ) LockRelease ( name string ) error {
s . releaseLocksLock . Lock ( )
defer s . releaseLocksLock . Unlock ( )
var lock * sync . Mutex
lock , exists := s . releaseLocks [ name ]
if ! exists {
releases , err := s . ListReleases ( )
if err != nil {
return err
}
found := false
for _ , release := range releases {
if release . Name == name {
found = true
}
}
if ! found {
return fmt . Errorf ( "Unable to lock release %s: release not found" , name )
}
lock = & sync . Mutex { }
s . releaseLocks [ name ] = lock
}
lock . Lock ( )
return nil
}
// UnlockRelease releases a mutually exclusive access to a release.
// If release doesn't exist or wasn't previously locked - the unlock will pass
func ( s * Storage ) UnlockRelease ( name string ) {
s . releaseLocksLock . Lock ( )
defer s . releaseLocksLock . Unlock ( )
var lock * sync . Mutex
lock , exists := s . releaseLocks [ name ]
if ! exists {
return
}
lock . Unlock ( )
}
// makeKey concatenates a release name and version into
// a string with format ```<release_name>#v<version>```.
// This key is used to uniquely identify storage objects.
@ -167,5 +218,9 @@ func Init(d driver.Driver) *Storage {
if d == nil {
d = driver . NewMemory ( )
}
return & Storage { Driver : d }
return & Storage {
Driver : d ,
releaseLocks : make ( map [ string ] * sync . Mutex ) ,
releaseLocksLock : & sync . Mutex { } ,
}
}