Skip to content

Commit 9af1cf5

Browse files
committed
Split model Step function
Signed-off-by: Marek Siarkowicz <siarkowicz@google.com>
1 parent 86fa2e0 commit 9af1cf5

File tree

1 file changed

+129
-104
lines changed

1 file changed

+129
-104
lines changed

tests/robustness/model/deterministic.go

Lines changed: 129 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -127,124 +127,149 @@ func freshEtcdState() EtcdState {
127127

128128
// Step handles a successful request, returning updated state and response it would generate.
129129
func (s EtcdState) Step(request EtcdRequest) (EtcdState, MaybeEtcdResponse) {
130-
// TODO: Avoid copying when TXN only has read operations
131-
if request.Type == Range {
132-
if request.Range.Revision == 0 || request.Range.Revision == s.Revision {
133-
resp := s.getRange(request.Range.RangeOptions)
134-
return s, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Range: &resp, Revision: s.Revision}}
135-
}
136-
if request.Range.Revision > s.Revision {
137-
return s, MaybeEtcdResponse{Error: ErrEtcdFutureRev.Error()}
138-
}
139-
if request.Range.Revision < s.CompactRevision {
140-
return s, MaybeEtcdResponse{EtcdResponse: EtcdResponse{ClientError: mvcc.ErrCompacted.Error()}}
141-
}
142-
return s, MaybeEtcdResponse{Persisted: true, PersistedRevision: s.Revision}
130+
switch request.Type {
131+
case Range:
132+
return s.stepRange(request)
133+
case Txn:
134+
return s.stepTxn(request)
135+
case LeaseGrant:
136+
return s.stepLeaseGrant(request)
137+
case LeaseRevoke:
138+
return s.stepLeaseRevoke(request)
139+
case Defragment:
140+
return s.stepDefragment(request)
141+
case Compact:
142+
return s.stepCompact(request)
143+
default:
144+
panic(fmt.Sprintf("Unknown request type: %v", request.Type))
143145
}
146+
}
144147

148+
func (s EtcdState) stepRange(request EtcdRequest) (EtcdState, MaybeEtcdResponse) {
149+
if request.Range.Revision == 0 || request.Range.Revision == s.Revision {
150+
resp := s.getRange(request.Range.RangeOptions)
151+
return s, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Range: &resp, Revision: s.Revision}}
152+
}
153+
if request.Range.Revision > s.Revision {
154+
return s, MaybeEtcdResponse{Error: ErrEtcdFutureRev.Error()}
155+
}
156+
if request.Range.Revision < s.CompactRevision {
157+
return s, MaybeEtcdResponse{EtcdResponse: EtcdResponse{ClientError: mvcc.ErrCompacted.Error()}}
158+
}
159+
return s, MaybeEtcdResponse{Persisted: true, PersistedRevision: s.Revision}
160+
}
161+
162+
func (s EtcdState) stepTxn(request EtcdRequest) (EtcdState, MaybeEtcdResponse) {
163+
// TODO: Avoid copying when TXN only has read operations
145164
newState := s.DeepCopy()
146-
switch request.Type {
147-
case Txn:
148-
failure := false
149-
for _, cond := range request.Txn.Conditions {
150-
val := newState.KeyValues[cond.Key]
151-
if cond.ExpectedVersion > 0 {
152-
if val.Version != cond.ExpectedVersion {
153-
failure = true
154-
break
155-
}
156-
} else if val.ModRevision != cond.ExpectedRevision {
165+
failure := false
166+
for _, cond := range request.Txn.Conditions {
167+
val := newState.KeyValues[cond.Key]
168+
if cond.ExpectedVersion > 0 {
169+
if val.Version != cond.ExpectedVersion {
157170
failure = true
158171
break
159172
}
173+
} else if val.ModRevision != cond.ExpectedRevision {
174+
failure = true
175+
break
160176
}
161-
operations := request.Txn.OperationsOnSuccess
162-
if failure {
163-
operations = request.Txn.OperationsOnFailure
164-
}
165-
opResp := make([]EtcdOperationResult, len(operations))
166-
increaseRevision := false
167-
for i, op := range operations {
168-
switch op.Type {
169-
case RangeOperation:
170-
opResp[i] = EtcdOperationResult{
171-
RangeResponse: newState.getRange(op.Range),
172-
}
173-
case PutOperation:
174-
_, leaseExists := newState.Leases[op.Put.LeaseID]
175-
if op.Put.LeaseID != 0 && !leaseExists {
176-
break
177-
}
178-
ver := int64(1)
179-
if val, exists := newState.KeyValues[op.Put.Key]; exists && val.Version > 0 {
180-
ver = val.Version + 1
181-
}
182-
newState.KeyValues[op.Put.Key] = ValueRevision{
183-
Value: op.Put.Value,
184-
ModRevision: newState.Revision + 1,
185-
Version: ver,
186-
}
177+
}
178+
operations := request.Txn.OperationsOnSuccess
179+
if failure {
180+
operations = request.Txn.OperationsOnFailure
181+
}
182+
opResp := make([]EtcdOperationResult, len(operations))
183+
increaseRevision := false
184+
for i, op := range operations {
185+
switch op.Type {
186+
case RangeOperation:
187+
opResp[i] = EtcdOperationResult{
188+
RangeResponse: newState.getRange(op.Range),
189+
}
190+
case PutOperation:
191+
_, leaseExists := newState.Leases[op.Put.LeaseID]
192+
if op.Put.LeaseID != 0 && !leaseExists {
193+
break
194+
}
195+
ver := int64(1)
196+
if val, exists := newState.KeyValues[op.Put.Key]; exists && val.Version > 0 {
197+
ver = val.Version + 1
198+
}
199+
newState.KeyValues[op.Put.Key] = ValueRevision{
200+
Value: op.Put.Value,
201+
ModRevision: newState.Revision + 1,
202+
Version: ver,
203+
}
204+
increaseRevision = true
205+
newState = detachFromOldLease(newState, op.Put.Key)
206+
if leaseExists {
207+
newState = attachToNewLease(newState, op.Put.LeaseID, op.Put.Key)
208+
}
209+
case DeleteOperation:
210+
if _, ok := newState.KeyValues[op.Delete.Key]; ok {
211+
delete(newState.KeyValues, op.Delete.Key)
187212
increaseRevision = true
188-
newState = detachFromOldLease(newState, op.Put.Key)
189-
if leaseExists {
190-
newState = attachToNewLease(newState, op.Put.LeaseID, op.Put.Key)
191-
}
192-
case DeleteOperation:
193-
if _, ok := newState.KeyValues[op.Delete.Key]; ok {
194-
delete(newState.KeyValues, op.Delete.Key)
195-
increaseRevision = true
196-
newState = detachFromOldLease(newState, op.Delete.Key)
197-
opResp[i].Deleted = 1
198-
}
199-
default:
200-
panic("unsupported operation")
213+
newState = detachFromOldLease(newState, op.Delete.Key)
214+
opResp[i].Deleted = 1
201215
}
216+
default:
217+
panic("unsupported operation")
202218
}
203-
if increaseRevision {
204-
newState.Revision++
205-
}
206-
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Txn: &TxnResponse{Failure: failure, Results: opResp}, Revision: newState.Revision}}
207-
case LeaseGrant:
208-
// Empty LeaseID means the request failed and client didn't get response. Ignore it as client cannot use lease without knowing its id.
209-
if request.LeaseGrant.LeaseID == 0 {
210-
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Revision: newState.Revision, LeaseGrant: &LeaseGrantReponse{}}}
211-
}
212-
lease := EtcdLease{
213-
LeaseID: request.LeaseGrant.LeaseID,
214-
Keys: map[string]struct{}{},
215-
}
216-
newState.Leases[request.LeaseGrant.LeaseID] = lease
219+
}
220+
if increaseRevision {
221+
newState.Revision++
222+
}
223+
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Txn: &TxnResponse{Failure: failure, Results: opResp}, Revision: newState.Revision}}
224+
}
225+
226+
func (s EtcdState) stepLeaseGrant(request EtcdRequest) (EtcdState, MaybeEtcdResponse) {
227+
newState := s.DeepCopy()
228+
// Empty LeaseID means the request failed and client didn't get response. Ignore it as client cannot use lease without knowing its id.
229+
if request.LeaseGrant.LeaseID == 0 {
217230
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Revision: newState.Revision, LeaseGrant: &LeaseGrantReponse{}}}
218-
case LeaseRevoke:
219-
// Delete the keys attached to the lease
220-
keyDeleted := false
221-
for key := range newState.Leases[request.LeaseRevoke.LeaseID].Keys {
222-
// same as delete.
223-
if _, ok := newState.KeyValues[key]; ok {
224-
if !keyDeleted {
225-
keyDeleted = true
226-
}
227-
delete(newState.KeyValues, key)
228-
delete(newState.KeyLeases, key)
231+
}
232+
lease := EtcdLease{
233+
LeaseID: request.LeaseGrant.LeaseID,
234+
Keys: map[string]struct{}{},
235+
}
236+
newState.Leases[request.LeaseGrant.LeaseID] = lease
237+
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Revision: newState.Revision, LeaseGrant: &LeaseGrantReponse{}}}
238+
}
239+
240+
func (s EtcdState) stepLeaseRevoke(request EtcdRequest) (EtcdState, MaybeEtcdResponse) {
241+
newState := s.DeepCopy()
242+
// Delete the keys attached to the lease
243+
keyDeleted := false
244+
for key := range newState.Leases[request.LeaseRevoke.LeaseID].Keys {
245+
// same as delete.
246+
if _, ok := newState.KeyValues[key]; ok {
247+
if !keyDeleted {
248+
keyDeleted = true
229249
}
250+
delete(newState.KeyValues, key)
251+
delete(newState.KeyLeases, key)
230252
}
231-
// delete the lease
232-
delete(newState.Leases, request.LeaseRevoke.LeaseID)
233-
if keyDeleted {
234-
newState.Revision++
235-
}
236-
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Revision: newState.Revision, LeaseRevoke: &LeaseRevokeResponse{}}}
237-
case Defragment:
238-
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Defragment: &DefragmentResponse{}, Revision: RevisionForNonLinearizableResponse}}
239-
case Compact:
240-
if request.Compact.Revision <= newState.CompactRevision {
241-
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{ClientError: mvcc.ErrCompacted.Error()}}
242-
}
243-
newState.CompactRevision = request.Compact.Revision
244-
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Compact: &CompactResponse{}, Revision: RevisionForNonLinearizableResponse}}
245-
default:
246-
panic(fmt.Sprintf("Unknown request type: %v", request.Type))
247253
}
254+
// delete the lease
255+
delete(newState.Leases, request.LeaseRevoke.LeaseID)
256+
if keyDeleted {
257+
newState.Revision++
258+
}
259+
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Revision: newState.Revision, LeaseRevoke: &LeaseRevokeResponse{}}}
260+
}
261+
262+
func (s EtcdState) stepDefragment(request EtcdRequest) (EtcdState, MaybeEtcdResponse) {
263+
return s, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Defragment: &DefragmentResponse{}, Revision: RevisionForNonLinearizableResponse}}
264+
}
265+
266+
func (s EtcdState) stepCompact(request EtcdRequest) (EtcdState, MaybeEtcdResponse) {
267+
newState := s.DeepCopy()
268+
if request.Compact.Revision <= newState.CompactRevision {
269+
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{ClientError: mvcc.ErrCompacted.Error()}}
270+
}
271+
newState.CompactRevision = request.Compact.Revision
272+
return newState, MaybeEtcdResponse{EtcdResponse: EtcdResponse{Compact: &CompactResponse{}, Revision: RevisionForNonLinearizableResponse}}
248273
}
249274

250275
func (s EtcdState) getRange(options RangeOptions) RangeResponse {

0 commit comments

Comments
 (0)