go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/node_utils.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 "google.golang.org/protobuf/proto" 19 20 kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api" 21 "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/internal/graph" 22 "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/internal/utils" 23 "go.ligato.io/vpp-agent/v3/proto/ligato/kvscheduler" 24 ) 25 26 func nodeToKVPairWithMetadata(node graph.Node) kvs.KVWithMetadata { 27 return kvs.KVWithMetadata{ 28 Key: node.GetKey(), 29 Value: node.GetValue(), 30 Metadata: node.GetMetadata(), 31 Origin: getNodeOrigin(node), 32 } 33 } 34 35 func nodesToKVPairsWithMetadata(nodes []graph.Node) (kvPairs []kvs.KVWithMetadata) { 36 for _, node := range nodes { 37 kvPairs = append(kvPairs, nodeToKVPairWithMetadata(node)) 38 } 39 return kvPairs 40 } 41 42 // constructTargets builds targets for the graph based on derived values and dependencies. 43 func constructTargets(deps []kvs.Dependency, derives []kvs.KeyValuePair) (targets []graph.RelationTargetDef) { 44 targets = make([]graph.RelationTargetDef, 0, len(deps)+len(derives)) 45 for _, dep := range deps { 46 target := graph.RelationTargetDef{ 47 Relation: DependencyRelation, 48 Label: dep.Label, 49 Key: dep.Key, 50 Selector: graph.TargetSelector{ 51 KeyPrefixes: dep.AnyOf.KeyPrefixes, 52 KeySelector: dep.AnyOf.KeySelector, 53 }, 54 } 55 targets = append(targets, target) 56 } 57 58 for _, derived := range derives { 59 target := graph.RelationTargetDef{ 60 Relation: DerivesRelation, 61 Label: derived.Key, 62 Key: derived.Key, 63 } 64 targets = append(targets, target) 65 } 66 67 return targets 68 } 69 70 // equalValueDetails compares value state details for equality. 71 func equalValueDetails(details1, details2 []string) bool { 72 if len(details1) != len(details2) { 73 return false 74 } 75 for _, d1 := range details1 { 76 found := false 77 for _, d2 := range details2 { 78 if d1 == d2 { 79 found = true 80 break 81 } 82 } 83 if !found { 84 return false 85 } 86 } 87 return true 88 } 89 90 // getValueDetails returns further details about the value state. 91 func getValueDetails(node graph.Node) (details []string) { 92 state := getNodeState(node) 93 _, err := getNodeError(node) 94 if state == kvscheduler.ValueState_INVALID { 95 if ivErr, isIVErr := err.(*kvs.InvalidValueError); isIVErr { 96 details = ivErr.GetInvalidFields() 97 return 98 } 99 } 100 if state == kvscheduler.ValueState_PENDING { 101 for _, targets := range node.GetTargets(DependencyRelation) { 102 satisfied := false 103 for _, target := range targets.Nodes { 104 if isNodeAvailable(target) { 105 satisfied = true 106 } 107 } 108 if !satisfied { 109 details = append(details, targets.Label) 110 } 111 } 112 } 113 return details 114 } 115 116 // getValueStatus reads the value status from the corresponding node. 117 func getValueStatus(node graph.Node, key string) *kvscheduler.BaseValueStatus { 118 status := &kvscheduler.BaseValueStatus{ 119 Value: &kvscheduler.ValueStatus{ 120 Key: key, 121 }, 122 } 123 124 status.Value.State = getNodeState(node) 125 if status.Value.State == kvscheduler.ValueState_NONEXISTENT { 126 // nothing else to get for non-existent value 127 return status 128 } 129 _, err := getNodeError(node) 130 if err != nil { 131 status.Value.Error = err.Error() 132 } 133 status.Value.LastOperation = getNodeLastOperation(node) 134 status.Value.State = getNodeState(node) 135 status.Value.Details = getValueDetails(node) 136 137 // derived nodes 138 if !isNodeDerived(node) { 139 for _, derivedNode := range getDerivedNodes(node) { 140 derValStatus := getValueStatus(derivedNode, derivedNode.GetKey()) 141 status.DerivedValues = append(status.DerivedValues, derValStatus.Value) 142 } 143 } 144 145 return status 146 } 147 148 // functions returns selectors selecting non-derived NB values. 149 func nbBaseValsSelectors() []graph.FlagSelector { 150 return []graph.FlagSelector{ 151 graph.WithoutFlags(&DerivedFlag{}), 152 graph.WithoutFlags(&ValueStateFlag{kvscheduler.ValueState_OBTAINED}), 153 } 154 } 155 156 // functions returns selectors selecting non-derived SB values. 157 func sbBaseValsSelectors() []graph.FlagSelector { 158 return []graph.FlagSelector{ 159 graph.WithoutFlags(&DerivedFlag{}), 160 graph.WithFlags(&ValueStateFlag{kvscheduler.ValueState_OBTAINED}), 161 } 162 } 163 164 // function returns selectors selecting non-derived values belonging to the given 165 // descriptor. 166 func descrValsSelectors(descriptor string, onlyAvailable bool) []graph.FlagSelector { 167 descrSel := graph.WithFlags(&DescriptorFlag{descriptor}) 168 baseSel := graph.WithoutFlags(&DerivedFlag{}) 169 if onlyAvailable { 170 return []graph.FlagSelector{ 171 descrSel, baseSel, graph.WithoutFlags(&UnavailValueFlag{}), 172 } 173 } 174 return []graph.FlagSelector{descrSel, baseSel} 175 } 176 177 // getNodeState returns state stored in the ValueState flag. 178 func getNodeState(node graph.Node) kvscheduler.ValueState { 179 if node != nil { 180 flag := node.GetFlag(ValueStateFlagIndex) 181 if flag != nil { 182 return flag.(*ValueStateFlag).valueState 183 } 184 } 185 return kvscheduler.ValueState_NONEXISTENT 186 } 187 188 func valueStateToOrigin(state kvscheduler.ValueState) kvs.ValueOrigin { 189 switch state { 190 case kvscheduler.ValueState_NONEXISTENT: 191 return kvs.UnknownOrigin 192 case kvscheduler.ValueState_OBTAINED: 193 return kvs.FromSB 194 } 195 return kvs.FromNB 196 } 197 198 // getNodeOrigin returns node origin based on the value state. 199 func getNodeOrigin(node graph.Node) kvs.ValueOrigin { 200 state := getNodeState(node) 201 return valueStateToOrigin(state) 202 } 203 204 // getNodeError returns node error stored in Error flag. 205 func getNodeError(node graph.Node) (retriable bool, err error) { 206 if node != nil { 207 errorFlag := node.GetFlag(ErrorFlagIndex) 208 if errorFlag != nil { 209 flag := errorFlag.(*ErrorFlag) 210 return flag.retriable, flag.err 211 } 212 } 213 return false, nil 214 } 215 216 // getNodeErrorString returns node error stored in Error flag as string. 217 func getNodeErrorString(node graph.Node) string { 218 _, err := getNodeError(node) 219 if err == nil { 220 return "" 221 } 222 return err.Error() 223 } 224 225 // getNodeLastUpdate returns info about the last update for a given node, stored in LastUpdate flag. 226 func getNodeLastUpdate(node graph.Node) *LastUpdateFlag { 227 if node == nil { 228 return nil 229 } 230 flag := node.GetFlag(LastUpdateFlagIndex) 231 if flag == nil { 232 return nil 233 } 234 return flag.(*LastUpdateFlag) 235 } 236 237 // getNodeLastAppliedValue return the last applied value for the given node 238 func getNodeLastAppliedValue(node graph.Node) proto.Message { 239 lastUpdate := getNodeLastUpdate(node) 240 if lastUpdate == nil { 241 return nil 242 } 243 return lastUpdate.value 244 } 245 246 // getNodeLastOperation returns last operation executed over the given node. 247 func getNodeLastOperation(node graph.Node) kvscheduler.TxnOperation { 248 if node != nil && getNodeState(node) != kvscheduler.ValueState_OBTAINED { 249 lastUpdate := getNodeLastUpdate(node) 250 if lastUpdate != nil { 251 return lastUpdate.txnOp 252 } 253 } 254 return kvscheduler.TxnOperation_UNDEFINED 255 } 256 257 func isNodeDerived(node graph.Node) bool { 258 return node.GetFlag(DerivedFlagIndex) != nil 259 } 260 261 func getNodeBaseKey(node graph.Node) string { 262 flag := node.GetFlag(DerivedFlagIndex) 263 if flag == nil { 264 return node.GetKey() 265 } 266 return flag.(*DerivedFlag).baseKey 267 } 268 269 // isNodePending checks whether the node is available for dependency resolution. 270 func isNodeAvailable(node graph.Node) bool { 271 if node == nil { 272 return false 273 } 274 return node.GetFlag(UnavailValueFlagIndex) == nil 275 } 276 277 // isNodeReady return true if the given node has all dependencies satisfied. 278 // Recursive calls are needed to handle circular dependencies - nodes of a strongly 279 // connected component are treated as if they were squashed into one. 280 func isNodeReady(node graph.Node) bool { 281 if getNodeOrigin(node) == kvs.FromSB { 282 // for SB values dependencies are not checked 283 return true 284 } 285 ready, _ := isNodeReadyRec(node, 0, make(map[string]int), false) 286 return ready 287 } 288 289 // isNodeReadyRec is a recursive call from within isNodeReady. 290 // visited = map{ key -> depth } 291 func isNodeReadyRec(node graph.Node, depth int, visited map[string]int, checkSCC bool) (ready bool, cycleDepth int) { 292 if targetDepth, wasVisited := visited[node.GetKey()]; wasVisited { 293 return true, targetDepth 294 } 295 cycleDepth = depth 296 visited[node.GetKey()] = depth 297 defer delete(visited, node.GetKey()) 298 299 ready = true // for zero dependencies 300 var satisfiedLabel bool 301 cb := func(target graph.Node, label string) (skipLabel, abort bool) { 302 if target == nil { // end of the available targets for this label 303 if !satisfiedLabel { 304 ready = false 305 abort = true 306 return 307 } 308 satisfiedLabel = false // clear for the next label 309 return 310 } 311 312 if getNodeState(target) == kvscheduler.ValueState_REMOVED { 313 // do not consider values that are (being) removed 314 return 315 } 316 317 if isNodeAvailable(target) { 318 satisfiedLabel = true 319 if !checkSCC { 320 skipLabel = true 321 return 322 } 323 } 324 325 // test if node is inside a strongly-connected component (treated as one node) 326 targetReady, targetCycleDepth := isNodeReadyRec(target, depth+1, visited, true) 327 if targetReady && targetCycleDepth <= depth { 328 // this node is reachable from the target 329 satisfiedLabel = true 330 if targetCycleDepth < cycleDepth { 331 // update how far back in the branch this node can reach following dependencies 332 cycleDepth = targetCycleDepth 333 } 334 } 335 return 336 } 337 338 node.IterTargets(DependencyRelation, cb) 339 return 340 } 341 342 func canNodeHaveMetadata(node graph.Node) bool { 343 return !isNodeDerived(node) 344 } 345 346 func getDerivedNodes(node graph.Node) (derived []graph.Node) { 347 for _, derivedNodes := range node.GetTargets(DerivesRelation) { 348 derived = append(derived, derivedNodes.Nodes...) 349 } 350 return derived 351 } 352 353 func getDerivedKeys(node graph.Node) utils.KeySet { 354 set := utils.NewSliceBasedKeySet() 355 for _, derived := range getDerivedNodes(node) { 356 set.Add(derived.GetKey()) 357 } 358 return set 359 }