Chromium Code Reviews| Index: appengine/cmd/dm/model/attempt.go |
| diff --git a/appengine/cmd/dm/model/attempt.go b/appengine/cmd/dm/model/attempt.go |
| index ec8ce5c6ce8935097ba8f721b8fd20d8cddf5c27..03c476e312d421181d2e9dc641cf398a7956935d 100644 |
| --- a/appengine/cmd/dm/model/attempt.go |
| +++ b/appengine/cmd/dm/model/attempt.go |
| @@ -10,12 +10,29 @@ import ( |
| "golang.org/x/net/context" |
| - "github.com/luci/luci-go/common/api/dm/service/v1" |
| - "github.com/luci/luci-go/common/bit_field" |
| + dm "github.com/luci/luci-go/common/api/dm/service/v1" |
| + bf "github.com/luci/luci-go/common/bit_field" |
| "github.com/luci/luci-go/common/clock" |
| google_pb "github.com/luci/luci-go/common/proto/google" |
| ) |
| +// AttemptRetryState indicates the current state of the Attempt's retry |
| +// counters. |
| +type AttemptRetryState struct { |
| + Failed uint32 |
| + Expired uint32 |
| + TimedOut uint32 |
| + Crashed uint32 |
| +} |
| + |
| +// Reset resets all of the AttemptRetryState counters. |
| +func (a *AttemptRetryState) Reset() { |
| + a.Failed = 0 |
|
dnj (Google)
2016/06/09 18:00:56
*a = AttemptRetryState{} !
iannucci
2016/06/15 00:46:01
mmmm tasty.
|
| + a.Expired = 0 |
| + a.TimedOut = 0 |
| + a.Crashed = 0 |
| +} |
| + |
| // Attempt is the datastore model for a DM Attempt. It has no parent key, but |
| // it may have the following children entities: |
| // * FwdDep |
| @@ -29,7 +46,21 @@ type Attempt struct { |
| Created time.Time |
| Modified time.Time |
| - State dm.Attempt_State |
| + State dm.Attempt_State |
| + RetryState AttemptRetryState |
| + |
| + // Only valid when State == ABNORMAL_FINISHED |
| + AbnormalFinish dm.AbnormalFinish |
|
dnj (Google)
2016/06/09 18:00:56
Why not make these pointers?
iannucci
2016/06/15 00:46:01
because luci/gae doesn't allow embed-by-pointer in
|
| + |
| + // Only valid when State == FINISHED |
| + ResultExpiration time.Time `gae:",noindex"` |
| + ResultSize uint32 `gae:",noindex"` |
| + |
| + // PersistentState is the last successful execution's returned |
| + // PersistentState. It is set whenever an execution for this Attempt finishes |
| + // sucessfully. This is denormalized with the Execution's |
| + // ResultPersistentState field. |
| + PersistentState string `gae:",noindex"` |
| // TODO(iannucci): Use CurExecution as a 'deps block version' |
| // then we can have an 'ANY' directive which executes the attempt as soon |
| @@ -45,22 +76,21 @@ type Attempt struct { |
| // (or 0 if no Executions have been made yet). |
| CurExecution uint32 |
| - // AddingDepsBitmap is valid only while Attempt is in 'AddingDeps'. |
| - // A field value of 0 means the backdep hasn't been added yet. |
| - AddingDepsBitmap bf.BitField `gae:",noindex" json:"-"` |
| - |
| - // WaitingDepBitmap is valid only while Attempt is in a Status of 'AddingDeps' |
| - // or 'Blocked'. |
| - // A field value of 0 means that the dep is currently waiting. |
| - WaitingDepBitmap bf.BitField `gae:",noindex" json:"-"` |
| - |
| - // Only valid while Attempt is Finished |
| - ResultExpiration time.Time |
| - ResultSize uint32 |
| + // DepMap is valid only while Attempt is in a State of EXECUTING or WAITING. |
| + // |
| + // The size of this field is inspected to deteremine what the next state after |
| + // EXECUTING is. If the size == 0, it means the Attempt should move to the |
| + // FINISHED state. Otherwise it means that the Attempt should move to the |
| + // WAITING state. |
| + // |
| + // A bit field value of 0 means that the dep is currently waiting, and a bit |
| + // value of 1 means that the coresponding dep is satisfined. The Attempt can |
| + // be unblocked from WAITING back to SCHEDULING when all bits are set to 1. |
| + DepMap bf.BitField `gae:",noindex" json:"-"` |
|
iannucci
2016/06/08 02:54:24
this is part of the state machine simplification;
|
| // A lazily-updated boolean to reflect that this Attempt is expired for |
| // queries. |
| - Expired bool |
| + ResultExpired bool |
| } |
| // MakeAttempt is a convenience function to create a new Attempt model in |
| @@ -77,6 +107,9 @@ func MakeAttempt(c context.Context, aid *dm.Attempt_ID) *Attempt { |
| // ModifyState changes the current state of this Attempt and updates its |
| // Modified timestamp. |
| func (a *Attempt) ModifyState(c context.Context, newState dm.Attempt_State) error { |
| + if a.State == newState { |
| + return nil |
| + } |
| if err := a.State.Evolve(newState); err != nil { |
| return err |
| } |
| @@ -93,15 +126,6 @@ func (a *Attempt) ModifyState(c context.Context, newState dm.Attempt_State) erro |
| return nil |
| } |
| -// MustModifyState is the same as ModifyState, except that it panics if the |
| -// state transition is invalid. |
| -func (a *Attempt) MustModifyState(c context.Context, newState dm.Attempt_State) { |
| - err := a.ModifyState(c, newState) |
| - if err != nil { |
| - panic(err) |
| - } |
| -} |
| - |
| // ToProto returns a dm proto version of this Attempt. |
| func (a *Attempt) ToProto(withData bool) *dm.Attempt { |
| ret := dm.Attempt{Id: &a.ID} |
| @@ -112,32 +136,19 @@ func (a *Attempt) ToProto(withData bool) *dm.Attempt { |
| } |
| // DataProto returns an Attempt.Data message for this Attempt. |
| -func (a *Attempt) DataProto() *dm.Attempt_Data { |
| - ret := (*dm.Attempt_Data)(nil) |
| +func (a *Attempt) DataProto() (ret *dm.Attempt_Data) { |
| switch a.State { |
| - case dm.Attempt_NEEDS_EXECUTION: |
| - ret = dm.NewAttemptNeedsExecution(a.Modified).Data |
| - |
| + case dm.Attempt_SCHEDULING: |
|
iannucci
2016/06/08 02:54:24
these changes are due to the state machine simplif
|
| + ret = dm.NewAttemptScheduling().Data |
| case dm.Attempt_EXECUTING: |
| ret = dm.NewAttemptExecuting(a.CurExecution).Data |
| - |
| - case dm.Attempt_ADDING_DEPS: |
| - addset := a.AddingDepsBitmap |
| - waitset := a.WaitingDepBitmap |
| - setlen := addset.Size() |
| - |
| - ret = dm.NewAttemptAddingDeps( |
| - setlen-addset.CountSet(), setlen-waitset.CountSet()).Data |
| - |
| - case dm.Attempt_BLOCKED: |
| - waitset := a.WaitingDepBitmap |
| - setlen := waitset.Size() |
| - |
| - ret = dm.NewAttemptBlocked(setlen - waitset.CountSet()).Data |
| - |
| + case dm.Attempt_WAITING: |
| + ret = dm.NewAttemptWaiting(a.DepMap.Size() - a.DepMap.CountSet()).Data |
| case dm.Attempt_FINISHED: |
| - ret = dm.NewAttemptFinished(a.ResultExpiration, a.ResultSize, "").Data |
| - |
| + ret = dm.NewAttemptFinished(a.ResultExpiration, a.ResultSize, "", |
| + string(a.PersistentState)).Data |
| + case dm.Attempt_ABNORMAL_FINISHED: |
| + ret = dm.NewAttemptAbnormalFinish(&a.AbnormalFinish).Data |
| default: |
| panic(fmt.Errorf("unknown Attempt_State: %s", a.State)) |
| } |