Merge pull request #2732 from hashicorp/b-persist-alloc-updates

Persist Alloc when EvalID changes
This commit is contained in:
Michael Schurter 2017-07-03 14:46:43 -07:00 committed by GitHub
commit 2d741c770b
1 changed files with 40 additions and 6 deletions

View File

@ -30,6 +30,7 @@ const (
var ( var (
// The following are the key paths written to the state database // The following are the key paths written to the state database
allocRunnerStateAllocKey = []byte("alloc")
allocRunnerStateImmutableKey = []byte("immutable") allocRunnerStateImmutableKey = []byte("immutable")
allocRunnerStateMutableKey = []byte("mutable") allocRunnerStateMutableKey = []byte("mutable")
allocRunnerStateAllocDirKey = []byte("alloc-dir") allocRunnerStateAllocDirKey = []byte("alloc-dir")
@ -81,6 +82,12 @@ type AllocRunner struct {
// stateDB is used to store the alloc runners state // stateDB is used to store the alloc runners state
stateDB *bolt.DB stateDB *bolt.DB
// persistedEval is the last persisted evaluation ID. Since evaluation
// IDs change on every allocation update we only need to persist the
// allocation when its eval ID != the last persisted eval ID.
persistedEvalLock sync.Mutex
persistedEval string
// immutablePersisted and allocDirPersisted are used to track whether the // immutablePersisted and allocDirPersisted are used to track whether the
// immutable data and the alloc dir have been persisted. Once persisted we // immutable data and the alloc dir have been persisted. Once persisted we
// can lower write volume by not re-writing these values // can lower write volume by not re-writing these values
@ -111,11 +118,15 @@ type allocRunnerState struct {
} `json:"Context,omitempty"` } `json:"Context,omitempty"`
} }
// allocRunnerImmutableState is state that only has to be written once as it // allocRunnerAllocState is state that only has to be written when the alloc
// doesn't change over the life-cycle of the alloc_runner. // changes.
type allocRunnerAllocState struct {
Alloc *structs.Allocation
}
// allocRunnerImmutableState is state that only has to be written once.
type allocRunnerImmutableState struct { type allocRunnerImmutableState struct {
Version string Version string
Alloc *structs.Allocation
} }
// allocRunnerMutableState is state that has to be written on each save as it // allocRunnerMutableState is state that has to be written on each save as it
@ -208,8 +219,12 @@ func (r *AllocRunner) RestoreState() error {
// Get the state objects // Get the state objects
var mutable allocRunnerMutableState var mutable allocRunnerMutableState
var immutable allocRunnerImmutableState var immutable allocRunnerImmutableState
var allocState allocRunnerAllocState
var allocDir allocdir.AllocDir var allocDir allocdir.AllocDir
if err := getObject(bkt, allocRunnerStateAllocKey, &allocState); err != nil {
return fmt.Errorf("failed to read alloc runner alloc state: %v", err)
}
if err := getObject(bkt, allocRunnerStateImmutableKey, &immutable); err != nil { if err := getObject(bkt, allocRunnerStateImmutableKey, &immutable); err != nil {
return fmt.Errorf("failed to read alloc runner immutable state: %v", err) return fmt.Errorf("failed to read alloc runner immutable state: %v", err)
} }
@ -221,7 +236,7 @@ func (r *AllocRunner) RestoreState() error {
} }
// Populate the fields // Populate the fields
r.alloc = immutable.Alloc r.alloc = allocState.Alloc
r.allocDir = &allocDir r.allocDir = &allocDir
r.allocClientStatus = mutable.AllocClientStatus r.allocClientStatus = mutable.AllocClientStatus
r.allocClientDescription = mutable.AllocClientDescription r.allocClientDescription = mutable.AllocClientDescription
@ -342,10 +357,29 @@ func (r *AllocRunner) saveAllocRunnerState() error {
return fmt.Errorf("failed to retrieve allocation bucket: %v", err) return fmt.Errorf("failed to retrieve allocation bucket: %v", err)
} }
// Write the immutable data // Write the allocation if the eval has changed
r.persistedEvalLock.Lock()
lastPersisted := r.persistedEval
r.persistedEvalLock.Unlock()
if alloc.EvalID != lastPersisted {
allocState := &allocRunnerAllocState{
Alloc: alloc,
}
if err := putObject(allocBkt, allocRunnerStateAllocKey, &allocState); err != nil {
return fmt.Errorf("failed to write alloc_runner alloc state: %v", err)
}
tx.OnCommit(func() {
r.persistedEvalLock.Lock()
r.persistedEval = alloc.EvalID
r.persistedEvalLock.Unlock()
})
}
// Write immutable data iff it hasn't been written yet
if !r.immutablePersisted { if !r.immutablePersisted {
immutable := &allocRunnerImmutableState{ immutable := &allocRunnerImmutableState{
Alloc: alloc,
Version: r.config.Version, Version: r.config.Version,
} }