@@ -20,6 +20,7 @@ import (
2020 "html"
2121 "maps"
2222 "reflect"
23+ "slices"
2324 "sort"
2425
2526 "github.com/anishathalye/porcupine"
@@ -163,7 +164,10 @@ func (s EtcdState) stepTxn(request EtcdRequest) (EtcdState, MaybeEtcdResponse) {
163164 newState := s .DeepCopy ()
164165 failure := false
165166 for _ , cond := range request .Txn .Conditions {
166- val := newState .KeyValues [cond .Key ]
167+ val , ok := newState .GetValue (cond .Key )
168+ if ! ok {
169+ val = & ValueRevision {}
170+ }
167171 if cond .ExpectedVersion > 0 {
168172 if val .Version != cond .ExpectedVersion {
169173 failure = true
@@ -187,29 +191,29 @@ func (s EtcdState) stepTxn(request EtcdRequest) (EtcdState, MaybeEtcdResponse) {
187191 RangeResponse : newState .getRange (op .Range ),
188192 }
189193 case PutOperation :
190- _ , leaseExists := newState .Leases [op .Put .LeaseID ]
191- if op .Put .LeaseID != 0 && ! leaseExists {
192- break
194+ var leaseID * int64
195+ if op .Put .LeaseID != 0 {
196+ if ! newState .leaseExists (op .Put .LeaseID ) {
197+ break
198+ }
199+ leaseID = & op .Put .LeaseID
193200 }
194201 ver := int64 (1 )
195- if val , exists := newState .KeyValues [op .Put .Key ]; exists && val .Version > 0 {
196- ver = val .Version + 1
202+ valPtr , exists := newState .GetValue (op .Put .Key )
203+ if exists && valPtr .Version > 0 {
204+ ver = valPtr .Version + 1
197205 }
198- newState . KeyValues [ op . Put . Key ] = ValueRevision {
206+ val : = ValueRevision {
199207 Value : op .Put .Value ,
200208 ModRevision : newState .Revision + 1 ,
201209 Version : ver ,
202210 }
211+ newState .setValueLease (op .Put .Key , val , leaseID )
203212 increaseRevision = true
204- newState = detachFromOldLease (newState , op .Put .Key )
205- if leaseExists {
206- newState = attachToNewLease (newState , op .Put .LeaseID , op .Put .Key )
207- }
208213 case DeleteOperation :
209- if _ , ok := newState .KeyValues [ op .Delete .Key ] ; ok {
210- delete ( newState .KeyValues , op .Delete .Key )
214+ if _ , ok := newState .GetValue ( op .Delete .Key ) ; ok {
215+ newState .deleteKey ( op .Delete .Key )
211216 increaseRevision = true
212- newState = detachFromOldLease (newState , op .Delete .Key )
213217 opResp [i ].Deleted = 1
214218 }
215219 default :
@@ -294,28 +298,69 @@ func (s EtcdState) getRange(options RangeOptions) RangeResponse {
294298 }
295299 response .Count = count
296300 } else {
297- value , ok := s .KeyValues [ options .Start ]
301+ valPtr , ok := s .GetValue ( options .Start )
298302 if ok {
299303 response .KVs = append (response .KVs , KeyValue {
300304 Key : options .Start ,
301- ValueRevision : value ,
305+ ValueRevision : * valPtr ,
302306 })
303307 response .Count = 1
304308 }
305309 }
306310 return response
307311}
308312
309- func detachFromOldLease (s EtcdState , key string ) EtcdState {
313+ func (s EtcdState ) KeysValueLeases () (keys []string , values []ValueRevision , leases []int64 ) {
314+ keys = make ([]string , 0 , len (s .KeyValues ))
315+ values = make ([]ValueRevision , 0 , len (s .KeyValues ))
316+ leases = make ([]int64 , 0 , len (s .KeyLeases ))
317+
318+ for k , v := range s .KeyValues {
319+ keys = append (keys , k )
320+ values = append (values , v )
321+ leases = append (leases , s .KeyLeases [k ])
322+ }
323+ return keys , values , leases
324+ }
325+
326+ func (s EtcdState ) leases () []int64 {
327+ return slices .Collect (maps .Keys (s .Leases ))
328+ }
329+
330+ func (s EtcdState ) GetValue (key string ) (* ValueRevision , bool ) {
331+ val , ok := s .KeyValues [key ]
332+ if ! ok {
333+ return nil , false
334+ }
335+ return & val , true
336+ }
337+
338+ func (s EtcdState ) setValueLease (key string , val ValueRevision , lease * int64 ) {
339+ s .KeyValues [key ] = val
310340 if oldLeaseID , ok := s .KeyLeases [key ]; ok {
311341 delete (s .Leases [oldLeaseID ].Keys , key )
342+ }
343+ if lease != nil {
344+ s .KeyLeases [key ] = * lease
345+ s .Leases [* lease ].Keys [key ] = leased
346+ } else {
312347 delete (s .KeyLeases , key )
313348 }
314- return s
315349}
316350
317- func attachToNewLease (s EtcdState , leaseID int64 , key string ) EtcdState {
318- s .KeyLeases [key ] = leaseID
319- s .Leases [leaseID ].Keys [key ] = leased
320- return s
351+ func (s EtcdState ) leaseExists (lease int64 ) bool {
352+ _ , ok := s .Leases [lease ]
353+ return ok
354+ }
355+
356+ func (s EtcdState ) deleteKey (key string ) {
357+ delete (s .KeyValues , key )
358+ if oldLeaseID , ok := s .KeyLeases [key ]; ok {
359+ delete (s .Leases [oldLeaseID ].Keys , key )
360+ }
361+ delete (s .KeyLeases , key )
362+ }
363+
364+ func (s EtcdState ) leaseKeys (leaseID int64 ) []string {
365+ return slices .Sorted (maps .Keys (s .Leases [leaseID ].Keys ))
321366}
0 commit comments