@@ -127,124 +127,149 @@ func freshEtcdState() EtcdState {
127
127
128
128
// Step handles a successful request, returning updated state and response it would generate.
129
129
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 ))
143
145
}
146
+ }
144
147
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
145
164
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 {
157
170
failure = true
158
171
break
159
172
}
173
+ } else if val .ModRevision != cond .ExpectedRevision {
174
+ failure = true
175
+ break
160
176
}
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 )
187
212
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
201
215
}
216
+ default :
217
+ panic ("unsupported operation" )
202
218
}
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 {
217
230
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
229
249
}
250
+ delete (newState .KeyValues , key )
251
+ delete (newState .KeyLeases , key )
230
252
}
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 ))
247
253
}
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 }}
248
273
}
249
274
250
275
func (s EtcdState ) getRange (options RangeOptions ) RangeResponse {
0 commit comments