go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/txn_exec.go (about) 1 // Copyright (c) 2018 Cisco and/or its affiliates. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package kvscheduler 16 17 import ( 18 "fmt" 19 "runtime/trace" 20 "sort" 21 "strings" 22 23 "google.golang.org/protobuf/proto" 24 25 "go.ligato.io/cn-infra/v2/logging" 26 27 kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api" 28 "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/internal/graph" 29 "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/internal/utils" 30 "go.ligato.io/vpp-agent/v3/proto/ligato/kvscheduler" 31 ) 32 33 // applyValueArgs collects all arguments to applyValue method. 34 type applyValueArgs struct { 35 graphW graph.RWAccess 36 txn *transaction 37 kv kvForTxn 38 baseKey string 39 40 applied utils.KeySet // set of values already(+being) applied 41 recreating utils.KeySet // set of values currently being re-created 42 43 isRetry bool 44 dryRun bool 45 46 // set inside of the recursive chain of applyValue-s 47 isDepUpdate bool 48 isDerived bool 49 50 // handling of dependency cycles 51 depth int 52 branch utils.KeySet 53 } 54 55 // executeTransaction executes pre-processed transaction. 56 // If <dry-run> is enabled, Validate/Create/Delete/Update operations will not be executed 57 // and the graph will be returned to its original state at the end. 58 func (s *Scheduler) executeTransaction(txn *transaction, graphW graph.RWAccess, dryRun bool) (executed kvs.RecordedTxnOps) { 59 op := "execute transaction" 60 if dryRun { 61 op = "simulate transaction" 62 } 63 defer trace.StartRegion(txn.ctx, op).End() 64 if dryRun { 65 defer trackTransactionMethod("simulateTransaction")() 66 } else { 67 defer trackTransactionMethod("executeTransaction")() 68 } 69 70 if s.logGraphWalk { 71 msg := fmt.Sprintf("%s (seqNum=%d)", op, txn.seqNum) 72 fmt.Printf("%s %s\n", nodeVisitBeginMark, msg) 73 defer fmt.Printf("%s %s\n", nodeVisitEndMark, msg) 74 } 75 76 branch := utils.NewMapBasedKeySet() // branch of current recursive calls to applyValue used to handle cycles 77 applied := utils.NewMapBasedKeySet() 78 79 prevValues := make([]kvs.KeyValuePair, 0, len(txn.values)) 80 81 // execute transaction either in best-effort mode or with revert on the first failure 82 var revert bool 83 for _, kv := range txn.values { 84 applied.Add(kv.key) 85 ops, prevValue, err := s.applyValue(&applyValueArgs{ 86 graphW: graphW, 87 txn: txn, 88 kv: kv, 89 baseKey: kv.key, 90 applied: applied, 91 dryRun: dryRun, 92 isRetry: txn.txnType == kvs.RetryFailedOps, 93 branch: branch, 94 }) 95 executed = append(executed, ops...) 96 prevValues = append(prevValues, kvs.KeyValuePair{}) 97 copy(prevValues[1:], prevValues) 98 prevValues[0] = prevValue 99 if err != nil { 100 if txn.txnType == kvs.NBTransaction && txn.nb.revertOnFailure { 101 // refresh failed value and trigger reverting 102 // (not dry-run) 103 failedKey := utils.NewSingletonKeySet(kv.key) 104 s.refreshGraph(graphW, failedKey, nil, true) 105 revert = true 106 break 107 } 108 } 109 } 110 111 if revert { 112 // record graph state in-between failure and revert 113 graphW.Release() 114 graphW = s.graph.Write(!dryRun, true) 115 116 // revert back to previous values 117 for _, kvPair := range prevValues { 118 ops, _, _ := s.applyValue(&applyValueArgs{ 119 graphW: graphW, 120 txn: txn, 121 kv: kvForTxn{ 122 key: kvPair.Key, 123 value: kvPair.Value, 124 origin: kvs.FromNB, 125 isRevert: true, 126 }, 127 baseKey: kvPair.Key, 128 applied: applied, 129 dryRun: dryRun, 130 branch: branch, 131 }) 132 executed = append(executed, ops...) 133 } 134 } 135 136 // get rid of uninteresting intermediate pending Create/Delete operations 137 executed = s.compressTxnOps(executed) 138 return executed 139 } 140 141 // applyValue applies new value received from NB or SB. 142 // It returns the list of executed operations. 143 func (s *Scheduler) applyValue(args *applyValueArgs) (executed kvs.RecordedTxnOps, prevValue kvs.KeyValuePair, err error) { 144 // dependency cycle detection 145 if cycle := args.branch.Has(args.kv.key); cycle { 146 return executed, prevValue, err 147 } 148 args.branch.Add(args.kv.key) 149 defer args.branch.Del(args.kv.key) 150 151 // verbose logging 152 if s.logGraphWalk { 153 endLog := s.logNodeVisit("applyValue", args) 154 defer endLog() 155 } 156 157 // create new revision of the node for the given key-value pair 158 node := args.graphW.SetNode(args.kv.key) 159 160 // remember previous value for a potential revert 161 prevValue.Key = node.GetKey() 162 prevValue.Value = node.GetValue() 163 164 // remember previous value status to detect and notify about changes 165 prevState := getNodeState(node) 166 prevOp := getNodeLastOperation(node) 167 prevErr := getNodeErrorString(node) 168 prevDetails := getValueDetails(node) 169 170 // prepare operation description - fill attributes that we can even before executing the operation 171 txnOp := s.preRecordTxnOp(args, node) 172 173 // determine the operation type 174 if args.isDepUpdate { 175 s.determineDepUpdateOperation(node, txnOp) 176 if txnOp.Operation == kvscheduler.TxnOperation_UNDEFINED { 177 // nothing needs to be updated 178 if node.GetValue() == nil { 179 // this value was already deleted (unsatisfied, derived) within 180 // the same cycle of runDepUpdates(), and we do not want to leak 181 // node with nil value 182 args.graphW.DeleteNode(args.kv.key) 183 } 184 return 185 } 186 } else if args.kv.value == nil { 187 txnOp.Operation = kvscheduler.TxnOperation_DELETE 188 } else if node.GetValue() == nil || !isNodeAvailable(node) { 189 txnOp.Operation = kvscheduler.TxnOperation_CREATE 190 } else { 191 txnOp.Operation = kvscheduler.TxnOperation_UPDATE 192 } 193 194 // remaining txnOp attributes to fill: 195 // NewState bool 196 // NewErr error 197 // NOOP bool 198 // IsRecreate bool 199 200 // update node flags 201 prevUpdate := getNodeLastUpdate(node) 202 lastUpdateFlag := &LastUpdateFlag{ 203 txnSeqNum: args.txn.seqNum, 204 txnOp: txnOp.Operation, 205 value: args.kv.value, 206 revert: args.kv.isRevert, 207 } 208 if args.txn.txnType == kvs.NBTransaction { 209 lastUpdateFlag.retryEnabled = args.txn.nb.retryEnabled 210 lastUpdateFlag.retryArgs = args.txn.nb.retryArgs 211 } else if prevUpdate != nil { 212 // inherit retry arguments from the last NB txn for this value 213 lastUpdateFlag.retryEnabled = prevUpdate.retryEnabled 214 lastUpdateFlag.retryArgs = prevUpdate.retryArgs 215 } else if args.isDerived { 216 // inherit from the parent value 217 parentNode := args.graphW.GetNode(args.baseKey) 218 prevParentUpdate := getNodeLastUpdate(parentNode) 219 if prevParentUpdate != nil { 220 lastUpdateFlag.retryEnabled = prevParentUpdate.retryEnabled 221 lastUpdateFlag.retryArgs = prevParentUpdate.retryArgs 222 } 223 224 } 225 node.SetFlags(lastUpdateFlag) 226 227 // if the value is already "broken" by this transaction, do not try to update 228 // anymore, unless this is a revert 229 // (needs to be refreshed first in the post-processing stage) 230 if (prevState == kvscheduler.ValueState_FAILED || prevState == kvscheduler.ValueState_RETRYING) && 231 !args.kv.isRevert && prevUpdate != nil && prevUpdate.txnSeqNum == args.txn.seqNum { 232 _, prevErr := getNodeError(node) 233 return executed, prevValue, prevErr 234 } 235 236 // run selected operation 237 switch txnOp.Operation { 238 case kvscheduler.TxnOperation_DELETE: 239 executed, err = s.applyDelete(node, txnOp, args, args.isDepUpdate, false) 240 case kvscheduler.TxnOperation_CREATE: 241 executed, err = s.applyCreate(node, txnOp, args) 242 case kvscheduler.TxnOperation_UPDATE: 243 executed, err = s.applyUpdate(node, txnOp, args) 244 } 245 246 // detect value state changes 247 if !args.dryRun { 248 nodeR := args.graphW.GetNode(args.kv.key) 249 if prevUpdate == nil || prevState != getNodeState(nodeR) || prevOp != getNodeLastOperation(nodeR) || 250 prevErr != getNodeErrorString(nodeR) || !equalValueDetails(prevDetails, getValueDetails(nodeR)) { 251 s.updatedStates.Add(args.baseKey) 252 } 253 } 254 255 return executed, prevValue, err 256 } 257 258 // applyDelete removes value. 259 func (s *Scheduler) applyDelete(node graph.NodeRW, txnOp *kvs.RecordedTxnOp, args *applyValueArgs, 260 pending, recreate bool) (executed kvs.RecordedTxnOps, err error) { 261 262 if s.logGraphWalk { 263 endLog := s.logNodeVisit("applyDelete", args) 264 defer endLog() 265 } 266 267 if node.GetValue() == nil { 268 // remove value that does not exist => noop (do not even record) 269 args.graphW.DeleteNode(args.kv.key) 270 return executed, nil 271 } 272 273 // reflect removal in the graph at the return 274 var ( 275 inheritedErr error 276 retriableErr bool 277 ) 278 prevState := getNodeState(node) 279 defer func() { 280 if inheritedErr != nil { 281 // revert back to available, derived value failed instead 282 node.DelFlags(UnavailValueFlagIndex) 283 s.updateNodeState(node, prevState, args) 284 return 285 } 286 if err == nil { 287 node.DelFlags(ErrorFlagIndex) 288 if pending { 289 // deleted due to missing dependencies 290 txnOp.NewState = kvscheduler.ValueState_PENDING 291 s.updateNodeState(node, txnOp.NewState, args) 292 } else { 293 // removed by request 294 txnOp.NewState = kvscheduler.ValueState_REMOVED 295 if args.isDerived && !recreate { 296 args.graphW.DeleteNode(args.kv.key) 297 } else { 298 s.updateNodeState(node, txnOp.NewState, args) 299 } 300 } 301 } else { 302 txnOp.NewErr = err 303 txnOp.NewErrMsg = err.Error() 304 txnOp.NewState = s.markFailedValue(node, args, err, retriableErr) 305 if !args.applied.Has(getNodeBaseKey(node)) { 306 // value removal not originating from this transaction 307 err = nil 308 } 309 } 310 executed = append(executed, txnOp) 311 }() 312 313 if !isNodeAvailable(node) { 314 // removing value that was pending => just update the state in the graph 315 txnOp.NOOP = true 316 return 317 } 318 319 // already mark as unavailable so that other nodes will not view it as satisfied 320 // dependency during removal 321 node.SetFlags(&UnavailValueFlag{}) 322 if !pending { 323 // state may still change if delete fails 324 s.updateNodeState(node, kvscheduler.ValueState_REMOVED, args) 325 } 326 327 // remove derived values 328 if !args.isDerived { 329 var derivedVals []kvForTxn 330 for _, derivedNode := range getDerivedNodes(node) { 331 derivedVals = append(derivedVals, kvForTxn{ 332 key: derivedNode.GetKey(), 333 value: nil, // delete 334 origin: args.kv.origin, 335 isRevert: args.kv.isRevert, 336 }) 337 } 338 var derExecs kvs.RecordedTxnOps 339 derExecs, inheritedErr = s.applyDerived(derivedVals, args, false) 340 executed = append(executed, derExecs...) 341 if inheritedErr != nil { 342 err = inheritedErr 343 return 344 } 345 } 346 347 // update values that depend on this kv-pair 348 depExecs, inheritedErr := s.runDepUpdates(node, args, false) 349 executed = append(executed, depExecs...) 350 if inheritedErr != nil { 351 err = inheritedErr 352 return 353 } 354 355 // execute delete operation 356 descriptor := s.registry.GetDescriptorForKey(node.GetKey()) 357 handler := newDescriptorHandler(descriptor) 358 if !args.dryRun && descriptor != nil { 359 if args.kv.origin != kvs.FromSB { 360 err = handler.delete(node.GetKey(), node.GetValue(), node.GetMetadata()) 361 } 362 if err != nil { 363 retriableErr = handler.isRetriableFailure(err) 364 } else if canNodeHaveMetadata(node) && descriptor.WithMetadata { 365 node.SetMetadata(nil) 366 } 367 } 368 return 369 } 370 371 // applyCreate creates new value which previously didn't exist or was unavailable. 372 func (s *Scheduler) applyCreate(node graph.NodeRW, txnOp *kvs.RecordedTxnOp, args *applyValueArgs) (executed kvs.RecordedTxnOps, err error) { 373 if s.logGraphWalk { 374 endLog := s.logNodeVisit("applyCreate", args) 375 defer endLog() 376 } 377 node.SetValue(args.kv.value) 378 379 // get descriptor 380 descriptor := s.registry.GetDescriptorForKey(args.kv.key) 381 handler := newDescriptorHandler(descriptor) 382 if descriptor != nil { 383 node.SetFlags(&DescriptorFlag{descriptor.Name}) 384 node.SetLabel(handler.keyLabel(args.kv.key)) 385 } 386 387 // handle unimplemented value 388 unimplemented := args.kv.origin == kvs.FromNB && !args.isDerived && descriptor == nil 389 if unimplemented { 390 if getNodeState(node) == kvscheduler.ValueState_UNIMPLEMENTED { 391 // already known 392 return 393 } 394 node.SetFlags(&UnavailValueFlag{}) 395 node.DelFlags(ErrorFlagIndex) 396 txnOp.NOOP = true 397 txnOp.NewState = kvscheduler.ValueState_UNIMPLEMENTED 398 s.updateNodeState(node, txnOp.NewState, args) 399 return kvs.RecordedTxnOps{txnOp}, nil 400 } 401 402 // mark derived value 403 if args.isDerived { 404 node.SetFlags(&DerivedFlag{baseKey: args.baseKey}) 405 } 406 407 // validate value 408 if !args.dryRun && args.kv.origin == kvs.FromNB { 409 err = handler.validate(node.GetKey(), node.GetValue()) 410 if err != nil { 411 node.SetFlags(&UnavailValueFlag{}) 412 txnOp.NewErr = err 413 txnOp.NewErrMsg = err.Error() 414 txnOp.NewState = kvscheduler.ValueState_INVALID 415 txnOp.NOOP = true 416 s.updateNodeState(node, txnOp.NewState, args) 417 node.SetFlags(&ErrorFlag{err: err, retriable: false}) 418 if !args.applied.Has(getNodeBaseKey(node)) { 419 // invalid value not originating from this transaction 420 err = nil 421 } 422 return kvs.RecordedTxnOps{txnOp}, err 423 } 424 } 425 426 // apply new relations 427 derives, updateExecs, inheritedErr := s.applyNewRelations(node, handler, nil, true, args) 428 executed = append(executed, updateExecs...) 429 if inheritedErr != nil { 430 // error is not expected here, executed operations should be NOOPs 431 err = inheritedErr 432 return 433 } 434 435 if !isNodeReady(node) { 436 // if not ready, nothing to do 437 node.SetFlags(&UnavailValueFlag{}) 438 node.DelFlags(ErrorFlagIndex) 439 txnOp.NewState = kvscheduler.ValueState_PENDING 440 txnOp.NOOP = true 441 s.updateNodeState(node, txnOp.NewState, args) 442 return kvs.RecordedTxnOps{txnOp}, nil 443 } 444 445 // execute Create operation 446 if !args.dryRun && descriptor != nil { 447 var metadata interface{} 448 449 if args.kv.origin != kvs.FromSB { 450 metadata, err = handler.create(node.GetKey(), node.GetValue()) 451 } else { 452 // already created in SB 453 metadata = args.kv.metadata 454 } 455 456 if err != nil { 457 // create failed => assume the value is unavailable 458 node.SetFlags(&UnavailValueFlag{}) 459 retriableErr := handler.isRetriableFailure(err) 460 txnOp.NewErr = err 461 txnOp.NewErrMsg = err.Error() 462 txnOp.NewState = s.markFailedValue(node, args, err, retriableErr) 463 if !args.applied.Has(getNodeBaseKey(node)) { 464 // value not originating from this transaction 465 err = nil 466 } 467 return kvs.RecordedTxnOps{txnOp}, err 468 } 469 470 // add metadata to the map 471 if canNodeHaveMetadata(node) && descriptor.WithMetadata { 472 node.SetMetadataMap(descriptor.Name) 473 node.SetMetadata(metadata) 474 } 475 } 476 477 // finalize node and save before going to derived values + dependencies 478 node.DelFlags(ErrorFlagIndex, UnavailValueFlagIndex) 479 if args.kv.origin == kvs.FromSB { 480 txnOp.NewState = kvscheduler.ValueState_OBTAINED 481 } else { 482 txnOp.NewState = kvscheduler.ValueState_CONFIGURED 483 } 484 s.updateNodeState(node, txnOp.NewState, args) 485 executed = append(executed, txnOp) 486 487 // update values that depend on this kv-pair 488 depExecs, inheritedErr := s.runDepUpdates(node, args, true) 489 executed = append(executed, depExecs...) 490 if inheritedErr != nil { 491 err = inheritedErr 492 return 493 } 494 495 // created derived values 496 if !args.isDerived { 497 var derivedVals []kvForTxn 498 for _, derivedVal := range derives { 499 derivedVals = append(derivedVals, kvForTxn{ 500 key: derivedVal.Key, 501 value: derivedVal.Value, 502 origin: args.kv.origin, 503 isRevert: args.kv.isRevert, 504 }) 505 } 506 derExecs, inheritedErr := s.applyDerived(derivedVals, args, true) 507 executed = append(executed, derExecs...) 508 if inheritedErr != nil { 509 err = inheritedErr 510 } 511 } 512 return 513 } 514 515 // applyUpdate applies new value to existing non-pending value. 516 func (s *Scheduler) applyUpdate(node graph.NodeRW, txnOp *kvs.RecordedTxnOp, args *applyValueArgs) (executed kvs.RecordedTxnOps, err error) { 517 if s.logGraphWalk { 518 endLog := s.logNodeVisit("applyUpdate", args) 519 defer endLog() 520 } 521 522 // validate new value 523 descriptor := s.registry.GetDescriptorForKey(args.kv.key) 524 handler := newDescriptorHandler(descriptor) 525 if !args.dryRun && args.kv.origin == kvs.FromNB { 526 err = handler.validate(node.GetKey(), args.kv.value) 527 if err != nil { 528 node.SetValue(args.kv.value) // save the invalid value 529 node.SetFlags(&UnavailValueFlag{}) 530 txnOp.NewErr = err 531 txnOp.NewErrMsg = err.Error() 532 txnOp.NewState = kvscheduler.ValueState_INVALID 533 txnOp.NOOP = true 534 s.updateNodeState(node, txnOp.NewState, args) 535 node.SetFlags(&ErrorFlag{err: err, retriable: false}) 536 if !args.applied.Has(getNodeBaseKey(node)) { 537 // invalid value not originating from this transaction 538 err = nil 539 } 540 return kvs.RecordedTxnOps{txnOp}, err 541 } 542 } 543 544 // compare new value with the old one 545 equivalent := handler.equivalentValues(node.GetKey(), node.GetValue(), args.kv.value) 546 547 // re-create the value if required by the descriptor 548 recreate := !equivalent && 549 args.kv.origin != kvs.FromSB && 550 handler.updateWithRecreate(args.kv.key, node.GetValue(), args.kv.value, node.GetMetadata()) 551 552 if recreate { 553 // mark keys which are being re-created for preRecordTxnOp 554 args.recreating = getDerivedKeys(node) 555 args.recreating.Add(node.GetKey()) 556 defer func() { args.recreating = nil }() 557 // remove the obsolete revision of the value 558 delOp := s.preRecordTxnOp(args, node) 559 delOp.Operation = kvscheduler.TxnOperation_DELETE 560 delOp.NewValue = nil 561 delExec, inheritedErr := s.applyDelete(node, delOp, args, false, true) 562 executed = append(executed, delExec...) 563 if inheritedErr != nil { 564 err = inheritedErr 565 return 566 } 567 // create the new revision of the value 568 node = args.graphW.SetNode(args.kv.key) 569 createOp := s.preRecordTxnOp(args, node) 570 createOp.Operation = kvscheduler.TxnOperation_CREATE 571 createOp.PrevValue = nil 572 createExec, inheritedErr := s.applyCreate(node, createOp, args) 573 executed = append(executed, createExec...) 574 err = inheritedErr 575 return 576 } 577 578 // save the new value 579 prevValue := node.GetValue() 580 node.SetValue(args.kv.value) 581 582 // apply new relations 583 derives, updateExecs, inheritedErr := s.applyNewRelations(node, handler, prevValue, !equivalent, args) 584 executed = append(executed, updateExecs...) 585 if inheritedErr != nil { 586 node.SetValue(prevValue) // revert back the original value 587 err = inheritedErr 588 return 589 } 590 591 // if the new dependencies are not satisfied => delete and set as pending with the new value 592 if !equivalent && !isNodeReady(node) { 593 node.SetValue(prevValue) // apply delete on the original value 594 delExec, inheritedErr := s.applyDelete(node, txnOp, args, true, false) 595 executed = append(executed, delExec...) 596 if inheritedErr != nil { 597 err = inheritedErr 598 } 599 node.SetValue(args.kv.value) 600 return 601 } 602 603 // execute update operation 604 if !args.dryRun && !equivalent && descriptor != nil { 605 var newMetadata interface{} 606 607 // call Update handler 608 if args.kv.origin != kvs.FromSB { 609 newMetadata, err = handler.update(node.GetKey(), prevValue, node.GetValue(), node.GetMetadata()) 610 } else { 611 // already modified in SB 612 newMetadata = args.kv.metadata 613 } 614 615 if err != nil { 616 retriableErr := handler.isRetriableFailure(err) 617 txnOp.NewErr = err 618 txnOp.NewErrMsg = err.Error() 619 txnOp.NewState = s.markFailedValue(node, args, err, retriableErr) 620 executed = append(executed, txnOp) 621 if !args.applied.Has(getNodeBaseKey(node)) { 622 // update not originating from this transaction 623 err = nil 624 } 625 return 626 } 627 628 // update metadata 629 if canNodeHaveMetadata(node) && descriptor.WithMetadata { 630 node.SetMetadata(newMetadata) 631 } 632 } 633 634 // finalize node and save before going to new/modified derived values + dependencies 635 node.DelFlags(ErrorFlagIndex, UnavailValueFlagIndex) 636 if args.kv.origin == kvs.FromSB { 637 txnOp.NewState = kvscheduler.ValueState_OBTAINED 638 } else { 639 txnOp.NewState = kvscheduler.ValueState_CONFIGURED 640 } 641 s.updateNodeState(node, txnOp.NewState, args) 642 643 // if the value was modified or the state changed, record operation 644 if !equivalent || txnOp.PrevState != txnOp.NewState { 645 // do not record transition if it only confirms that the value is in sync 646 confirmsInSync := equivalent && 647 txnOp.PrevState == kvscheduler.ValueState_DISCOVERED && 648 txnOp.NewState == kvscheduler.ValueState_CONFIGURED 649 if !confirmsInSync { 650 txnOp.NOOP = equivalent 651 executed = append(executed, txnOp) 652 } 653 } 654 655 if !args.isDerived { 656 // update/create derived values 657 var derivedVals []kvForTxn 658 for _, derivedVal := range derives { 659 derivedVals = append(derivedVals, kvForTxn{ 660 key: derivedVal.Key, 661 value: derivedVal.Value, 662 origin: args.kv.origin, 663 isRevert: args.kv.isRevert, 664 }) 665 } 666 derExecs, inheritedErr := s.applyDerived(derivedVals, args, true) 667 executed = append(executed, derExecs...) 668 if inheritedErr != nil { 669 err = inheritedErr 670 } 671 } 672 return 673 } 674 675 // applyNewRelations updates relation definitions and removes obsolete derived 676 // values. 677 func (s *Scheduler) applyNewRelations(node graph.NodeRW, handler *descriptorHandler, 678 prevValue proto.Message, updateDeps bool, 679 args *applyValueArgs) (derivedVals []kvs.KeyValuePair, executed kvs.RecordedTxnOps, err error) { 680 681 if args.isDerived && !updateDeps { 682 // nothing to update 683 return 684 } 685 686 // get the set of derived keys before update 687 prevDerivedKeys := utils.NewSliceBasedKeySet() 688 if !args.isDerived && prevValue != nil { 689 for _, kv := range handler.derivedValues(node.GetKey(), prevValue) { 690 prevDerivedKeys.Add(kv.Key) 691 } 692 } 693 694 // get the set of derived keys after update 695 newDerivedKeys := utils.NewSliceBasedKeySet() 696 if !args.isDerived { 697 derivedVals = handler.derivedValues(node.GetKey(), node.GetValue()) 698 for _, kv := range derivedVals { 699 newDerivedKeys.Add(kv.Key) 700 } 701 } 702 updateDerived := !prevDerivedKeys.Equals(newDerivedKeys) 703 if updateDeps || updateDerived { 704 dependencies := handler.dependencies(node.GetKey(), node.GetValue()) 705 node.SetTargets(constructTargets(dependencies, derivedVals)) 706 } 707 708 // remove obsolete derived values 709 if updateDerived { 710 var obsoleteDerVals []kvForTxn 711 prevDerivedKeys.Subtract(newDerivedKeys) 712 for _, obsolete := range prevDerivedKeys.Iterate() { 713 obsoleteDerVals = append(obsoleteDerVals, kvForTxn{ 714 key: obsolete, 715 value: nil, // delete 716 origin: args.kv.origin, 717 isRevert: args.kv.isRevert, 718 }) 719 } 720 if len(obsoleteDerVals) > 0 { 721 executed, err = s.applyDerived(obsoleteDerVals, args, false) 722 } 723 } 724 return 725 } 726 727 // applyDerived (re-)applies the given list of derived values. 728 func (s *Scheduler) applyDerived(derivedVals []kvForTxn, args *applyValueArgs, check bool) (executed kvs.RecordedTxnOps, err error) { 729 var wasErr error 730 if s.logGraphWalk { 731 endLog := s.logNodeVisit("applyDerived", args) 732 defer endLog() 733 } 734 735 // order derivedVals by key (just for deterministic behaviour which simplifies testing) 736 sort.Slice(derivedVals, func(i, j int) bool { return derivedVals[i].key < derivedVals[j].key }) 737 738 for _, derived := range derivedVals { 739 if check && !s.validDerivedKV(args.graphW, derived, args.txn.seqNum) { 740 continue 741 } 742 derArgs := *args 743 derArgs.kv = derived 744 derArgs.isDerived = true 745 derArgs.isDepUpdate = false 746 ops, _, err := s.applyValue(&derArgs) 747 if err != nil { 748 wasErr = err 749 } 750 executed = append(executed, ops...) 751 } 752 return executed, wasErr 753 } 754 755 // runDepUpdates triggers dependency updates on all nodes that depend on the given node. 756 func (s *Scheduler) runDepUpdates(node graph.Node, args *applyValueArgs, forUnavailable bool) (executed kvs.RecordedTxnOps, err error) { 757 if s.logGraphWalk { 758 endLog := s.logNodeVisit("runDepUpdates", args) 759 defer endLog() 760 } 761 762 var wasErr error 763 var depNodes []graph.Node 764 for _, depPerLabel := range node.GetSources(DependencyRelation) { 765 depNodes = append(depNodes, depPerLabel.Nodes...) 766 } 767 768 // order depNodes by key (just for deterministic behaviour which simplifies testing) 769 sort.Slice(depNodes, func(i, j int) bool { return depNodes[i].GetKey() < depNodes[j].GetKey() }) 770 771 for _, depNode := range depNodes { 772 if getNodeOrigin(depNode) != kvs.FromNB { 773 continue 774 } 775 if !isNodeAvailable(depNode) != forUnavailable { 776 continue 777 } 778 var value proto.Message 779 if lastUpdate := getNodeLastUpdate(depNode); lastUpdate != nil { 780 value = lastUpdate.value 781 } else { 782 // state=DISCOVERED 783 value = depNode.GetValue() 784 } 785 depArgs := *args 786 depArgs.kv = kvForTxn{ 787 key: depNode.GetKey(), 788 value: value, 789 origin: getNodeOrigin(depNode), 790 isRevert: args.kv.isRevert, 791 } 792 depArgs.baseKey = getNodeBaseKey(depNode) 793 depArgs.isDerived = isNodeDerived(depNode) 794 depArgs.isDepUpdate = true 795 ops, _, err := s.applyValue(&depArgs) 796 if err != nil { 797 wasErr = err 798 } 799 executed = append(executed, ops...) 800 } 801 return executed, wasErr 802 } 803 804 // determineDepUpdateOperation determines if the value needs update wrt. dependencies 805 // and what operation to execute. 806 func (s *Scheduler) determineDepUpdateOperation(node graph.NodeRW, txnOp *kvs.RecordedTxnOp) { 807 // create node if dependencies are now all met 808 if !isNodeAvailable(node) { 809 if !isNodeReady(node) { 810 // nothing to do 811 return 812 } 813 txnOp.Operation = kvscheduler.TxnOperation_CREATE 814 } else if !isNodeReady(node) { 815 // node should not be available anymore 816 txnOp.Operation = kvscheduler.TxnOperation_DELETE 817 } 818 } 819 820 // compressTxnOps removes uninteresting intermediate pending Create/Delete operations. 821 func (s *Scheduler) compressTxnOps(executed kvs.RecordedTxnOps) kvs.RecordedTxnOps { 822 // compress Create operations 823 compressed := make(kvs.RecordedTxnOps, 0, len(executed)) 824 for i, op := range executed { 825 compressedOp := false 826 if op.Operation == kvscheduler.TxnOperation_CREATE && op.NewState == kvscheduler.ValueState_PENDING { 827 for j := i + 1; j < len(executed); j++ { 828 if executed[j].Key == op.Key { 829 if executed[j].Operation == kvscheduler.TxnOperation_CREATE { 830 // compress 831 compressedOp = true 832 executed[j].PrevValue = op.PrevValue 833 executed[j].PrevErr = op.PrevErr 834 if op.PrevErr != nil { 835 executed[j].PrevErrMsg = op.PrevErr.Error() 836 } 837 executed[j].PrevState = op.PrevState 838 } 839 break 840 } 841 } 842 } 843 if !compressedOp { 844 compressed = append(compressed, op) 845 } 846 } 847 848 // compress Delete operations 849 length := len(compressed) 850 for i := length - 1; i >= 0; i-- { 851 op := compressed[i] 852 compressedOp := false 853 if op.Operation == kvscheduler.TxnOperation_DELETE && op.PrevState == kvscheduler.ValueState_PENDING { 854 for j := i - 1; j >= 0; j-- { 855 if compressed[j].Key == op.Key { 856 if compressed[j].Operation == kvscheduler.TxnOperation_DELETE { 857 // compress 858 compressedOp = true 859 compressed[j].NewValue = op.NewValue 860 compressed[j].NewErr = op.NewErr 861 if op.NewErr != nil { 862 compressed[j].NewErrMsg = op.NewErr.Error() 863 } 864 compressed[j].NewState = op.NewState 865 } 866 break 867 } 868 } 869 } 870 if compressedOp { 871 copy(compressed[i:], compressed[i+1:]) 872 length-- 873 } 874 } 875 compressed = compressed[:length] 876 return compressed 877 } 878 879 // updateNodeState updates node state if it is really necessary. 880 func (s *Scheduler) updateNodeState(node graph.NodeRW, newState kvscheduler.ValueState, args *applyValueArgs) { 881 if getNodeState(node) != newState { 882 if s.logGraphWalk { 883 indent := strings.Repeat(" ", (args.depth+1)*2) 884 fmt.Printf("%s-> change value state from %v to %v\n", indent, getNodeState(node), newState) 885 } 886 node.SetFlags(&ValueStateFlag{valueState: newState}) 887 } 888 } 889 890 func (s *Scheduler) markFailedValue(node graph.NodeRW, args *applyValueArgs, err error, 891 retriableErr bool) (newState kvscheduler.ValueState) { 892 893 // decide value state between FAILED and RETRYING 894 newState = kvscheduler.ValueState_FAILED 895 toBeReverted := args.txn.txnType == kvs.NBTransaction && args.txn.nb.revertOnFailure && !args.kv.isRevert 896 if retriableErr && !toBeReverted { 897 // consider operation retry 898 var alreadyRetried bool 899 if args.txn.txnType == kvs.RetryFailedOps { 900 baseKey := getNodeBaseKey(node) 901 _, alreadyRetried = args.txn.retry.keys[baseKey] 902 } 903 attempt := 1 904 if alreadyRetried { 905 attempt = args.txn.retry.attempt + 1 906 } 907 lastUpdate := getNodeLastUpdate(node) 908 if lastUpdate.retryEnabled && lastUpdate.retryArgs != nil && 909 (lastUpdate.retryArgs.MaxCount == 0 || attempt <= lastUpdate.retryArgs.MaxCount) { 910 // retry is allowed 911 newState = kvscheduler.ValueState_RETRYING 912 } 913 } 914 s.updateNodeState(node, newState, args) 915 node.SetFlags(&ErrorFlag{err: err, retriable: retriableErr}) 916 return newState 917 } 918 919 func (s *Scheduler) logNodeVisit(operation string, args *applyValueArgs) func() { 920 msg := fmt.Sprintf("%s (key = %s)", operation, args.kv.key) 921 args.depth++ 922 indent := strings.Repeat(" ", args.depth*2) 923 fmt.Printf("%s%s %s\n", indent, nodeVisitBeginMark, msg) 924 return func() { 925 args.depth-- 926 fmt.Printf("%s%s %s\n", indent, nodeVisitEndMark, msg) 927 } 928 } 929 930 // validDerivedKV check validity of a derived KV pair. 931 func (s *Scheduler) validDerivedKV(graphR graph.ReadAccess, kv kvForTxn, txnSeqNum uint64) bool { 932 node := graphR.GetNode(kv.key) 933 if kv.value == nil { 934 s.Log.WithFields(logging.Fields{ 935 "txnSeqNum": txnSeqNum, 936 "key": kv.key, 937 }).Warn("Derived nil value") 938 return false 939 } 940 if node != nil { 941 if !isNodeDerived(node) { 942 s.Log.WithFields(logging.Fields{ 943 "txnSeqNum": txnSeqNum, 944 "value": kv.value, 945 "key": kv.key, 946 }).Warn("Skipping derived value colliding with a base value") 947 return false 948 } 949 } 950 return true 951 }