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  }