go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/internal/graph/node_write.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 graph 16 17 import ( 18 "reflect" 19 "sort" 20 21 "google.golang.org/protobuf/proto" 22 23 "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/internal/utils" 24 ) 25 26 type node struct { 27 *nodeR 28 29 metaInSync bool 30 dataUpdated bool 31 targetsUpdated bool 32 sourcesUpdated bool 33 } 34 35 // newNode creates a new instance of node, either built from the scratch or 36 // extending existing nodeR. 37 func newNode(nodeR *nodeR) *node { 38 if nodeR == nil { 39 return &node{ 40 nodeR: newNodeR(), 41 metaInSync: true, 42 dataUpdated: true, /* completely new node */ 43 } 44 } 45 return &node{ 46 nodeR: nodeR, 47 metaInSync: true, 48 } 49 } 50 51 // SetLabel associates given label with this node. 52 func (node *node) SetLabel(label string) { 53 node.label = label 54 node.dataUpdated = true 55 } 56 57 // SetValue associates given value with this node. 58 func (node *node) SetValue(value proto.Message) { 59 node.value = value 60 node.dataUpdated = true 61 } 62 63 // SetFlags associates given flag with this node. 64 func (node *node) SetFlags(flags ...Flag) { 65 for _, flag := range flags { 66 node.flags[flag.GetIndex()] = flag 67 } 68 node.dataUpdated = true 69 } 70 71 // DelFlags removes given flag from this node. 72 func (node *node) DelFlags(flagIndexes ...int) { 73 for _, idx := range flagIndexes { 74 node.flags[idx] = nil 75 } 76 node.dataUpdated = true 77 } 78 79 // SetMetadataMap chooses metadata map to be used to store the association 80 // between this node's value label and metadata. 81 func (node *node) SetMetadataMap(mapName string) { 82 if node.metadataMap == "" { // cannot be changed 83 node.metadataMap = mapName 84 node.dataUpdated = true 85 node.metaInSync = false 86 if !node.graph.wCopy { 87 node.syncMetadata() 88 } 89 } 90 } 91 92 // SetMetadata associates given value metadata with this node. 93 func (node *node) SetMetadata(metadata interface{}) { 94 node.metadata = metadata 95 node.dataUpdated = true 96 node.metaInSync = false 97 if !node.graph.wCopy { 98 node.syncMetadata() 99 } 100 } 101 102 // syncMetadata applies metadata changes into the associated mapping. 103 func (node *node) syncMetadata() { 104 if node.metaInSync { 105 return 106 } 107 // update metadata map 108 if mapping, hasMapping := node.graph.mappings[node.metadataMap]; hasMapping { 109 if node.metadataAdded { 110 if node.metadata == nil { 111 mapping.Delete(node.label) 112 node.metadataAdded = false 113 } else { 114 prevMeta, _ := mapping.GetValue(node.label) 115 if !reflect.DeepEqual(prevMeta, node.metadata) { 116 mapping.Update(node.label, node.metadata) 117 } 118 } 119 } else if node.metadata != nil { 120 mapping.Put(node.label, node.metadata) 121 node.metadataAdded = true 122 } 123 } 124 node.metaInSync = true 125 } 126 127 // SetTargets updates definitions of all edges pointing from this node. 128 func (node *node) SetTargets(targetsDef []RelationTargetDef) { 129 130 pgraph := node.graph.parent 131 if pgraph != nil && pgraph.methodTracker != nil { 132 defer pgraph.methodTracker("Node.SetTargets")() 133 } 134 135 sort.Slice(targetsDef, func(i, j int) bool { 136 _, order := targetsDef[i].Compare(targetsDef[j]) 137 return order == -1 138 }) 139 140 var i, j int 141 for i < len(targetsDef) || j < len(node.targetsDef) { 142 var equal bool 143 var order int 144 if i < len(targetsDef) && j < len(node.targetsDef) { 145 equal, order = targetsDef[i].Compare(node.targetsDef[j]) 146 } else if i < len(targetsDef) { 147 equal = false 148 order = -1 149 } else { 150 equal = false 151 order = 1 152 } 153 if equal { 154 if targetsDef[i].WithKeySelector() { 155 // re-run key selector 156 target := &node.targets[i] 157 // -> remove obsolete targets 158 var obsolete []string 159 for _, key := range target.MatchingKeys.Iterate() { 160 if !targetsDef[i].Selector.KeySelector(key) { 161 obsolete = append(obsolete, key) 162 } 163 } 164 for _, key := range obsolete { 165 target.MatchingKeys.Del(key) 166 targetNode := node.graph.nodes[key] 167 targetNode.removeFromSources(target.Relation, target.Label, node.key) 168 } 169 // -> check for new targets 170 node.iterEveryEdge(targetsDef[i], func(key string) { 171 targetNode := node.graph.nodes[key] 172 node.addToTargets(targetNode, target) 173 }) 174 } 175 i++ 176 j++ 177 continue 178 } 179 180 // not equal, process the first in the order 181 if order == 0 { 182 // updated target definition 183 target := &node.targets[i] 184 target.ExpectedKey = expectedKey(targetsDef[i]) 185 // remove previous edges 186 for _, key := range target.MatchingKeys.Iterate() { 187 targetNode := node.graph.nodes[key] 188 targetNode.removeFromSources(target.Relation, target.Label, node.key) 189 } 190 node.addDelEdges(node.targetsDef[j], true) 191 // create new edges 192 if targetsDef[i].Singleton() { 193 target.MatchingKeys = utils.NewSingletonKeySet("") 194 } else { 195 // selector 196 target.MatchingKeys = utils.NewSliceBasedKeySet() 197 } 198 node.addDelEdges(targetsDef[i], false) 199 node.iterEveryEdge(targetsDef[i], func(key string) { 200 targetNode := node.graph.nodes[key] 201 node.addToTargets(targetNode, target) 202 }) 203 i++ 204 j++ 205 continue 206 } 207 if order == -1 { 208 // new target definition 209 node.addDelEdges(targetsDef[i], false) 210 node.addTargetEntry(i, targetsDef[i].Relation, targetsDef[i].Label, 211 targetsDef[i].Singleton()) 212 target := &node.targets[i] 213 target.ExpectedKey = expectedKey(targetsDef[i]) 214 node.iterEveryEdge(targetsDef[i], func(key string) { 215 targetNode := node.graph.nodes[key] 216 node.addToTargets(targetNode, target) 217 218 }) 219 i++ 220 continue 221 } 222 if order == 1 { 223 // obsolete target definition 224 target := &node.targets[i] 225 for _, key := range target.MatchingKeys.Iterate() { 226 targetNode := node.graph.nodes[key] 227 targetNode.removeFromSources(target.Relation, target.Label, node.key) 228 } 229 node.addDelEdges(node.targetsDef[j], true) 230 node.removeTargetEntry(i) 231 j++ 232 continue 233 } 234 } 235 236 node.targetsDef = targetsDef 237 node.dataUpdated = true 238 // check implementation: 239 if len(node.targetsDef) != len(node.targets) { 240 panic("SetTargets: len(node.targetsDef) != len(node.targets)") 241 } 242 } 243 244 // addTargetEntry adds new target entry at the given index. 245 func (node *node) addTargetEntry(index int, relation, label string, singleton bool) { 246 node.targets = append(node.targets, Target{}) 247 if index < len(node.targets)-1 { 248 copy(node.targets[index+1:], node.targets[index:]) 249 } 250 node.targets[index].Relation = relation 251 node.targets[index].Label = label 252 node.targets[index].ExpectedKey = "" 253 node.targets[index].MatchingKeys = utils.NewSliceBasedKeySet() 254 if singleton { 255 node.targets[index].MatchingKeys = utils.NewSingletonKeySet("") 256 } else { 257 // selector 258 node.targets[index].MatchingKeys = utils.NewSliceBasedKeySet() 259 } 260 } 261 262 // removeTargetEntry removes target entry at the given index 263 func (node *node) removeTargetEntry(index int) { 264 if index < len(node.targets)-1 { 265 copy(node.targets[index:], node.targets[index+1:]) 266 } 267 node.targets = node.targets[0 : len(node.targets)-1] 268 } 269 270 func (node *node) addDelEdges(target RelationTargetDef, del bool) { 271 cb := node.graph.edgeLookup.addEdge 272 if del { 273 cb = node.graph.edgeLookup.delEdge 274 } 275 if target.Key != "" { 276 cb(edge{ 277 targetKey: target.Key, 278 isPrefix: false, 279 sourceNode: node.key, 280 relation: target.Relation, 281 label: target.Label, 282 }) 283 } else { 284 for _, keyPrefix := range target.Selector.KeyPrefixes { 285 cb(edge{ 286 targetKey: keyPrefix, 287 isPrefix: true, 288 sourceNode: node.key, 289 relation: target.Relation, 290 label: target.Label, 291 }) 292 } 293 if len(target.Selector.KeyPrefixes) == 0 { 294 cb(edge{ 295 targetKey: "", 296 isPrefix: true, 297 sourceNode: node.key, 298 relation: target.Relation, 299 label: target.Label, 300 }) 301 } 302 } 303 } 304 305 // iterEveryEdge iterates over every outgoing edge. 306 func (node *node) iterEveryEdge(target RelationTargetDef, cb func(targetKey string)) { 307 checkTarget := func(key string) { 308 if !target.WithKeySelector() || target.Selector.KeySelector(key) { 309 cb(key) 310 } 311 } 312 if target.Key != "" { 313 node.graph.edgeLookup.iterTargets(target.Key, false, checkTarget) 314 return 315 } 316 if len(target.Selector.KeyPrefixes) == 0 { 317 node.graph.edgeLookup.iterTargets("", true, checkTarget) 318 } 319 for _, keyPrefix := range target.Selector.KeyPrefixes { 320 node.graph.edgeLookup.iterTargets(keyPrefix, true, checkTarget) 321 } 322 } 323 324 // addToTargets adds node2 into the set of targets for this node. 325 // Sources of node2 are also updated accordingly. 326 func (node *node) addToTargets(node2 *node, target *Target) { 327 // update targets of node 328 updated := target.MatchingKeys.Add(node2.key) 329 node.targetsUpdated = updated || node.targetsUpdated 330 if !updated { 331 return 332 } 333 node.graph.unsaved.Add(node.key) 334 335 // update sources of node2 336 node2.addToSources(node, target) 337 } 338 339 // addToSources adds node2 into the set of sources for this node. 340 func (node *node) addToSources(node2 *node, target *Target) { 341 s, idx := node.sources.GetTargetForLabel(target.Relation, target.Label) 342 if s == nil { 343 node.sources = append(node.sources, Target{}) 344 if idx < len(node.sources)-1 { 345 copy(node.sources[idx+1:], node.sources[idx:]) 346 } 347 node.sources[idx].Relation = target.Relation 348 node.sources[idx].Label = target.Label 349 node.sources[idx].MatchingKeys = utils.NewSliceBasedKeySet() 350 s = &(node.sources[idx]) 351 } 352 updated := s.MatchingKeys.Add(node2.key) 353 node.sourcesUpdated = updated || node.sourcesUpdated 354 if updated { 355 node.graph.unsaved.Add(node.key) 356 } 357 } 358 359 // removeFromTarget removes given key from the given target. 360 // Note: sources are not updated! 361 func (node *node) removeFromTarget(key, relation, label string) { 362 target, _ := node.targets.GetTargetForLabel(relation, label) 363 updated := target.MatchingKeys.Del(key) 364 node.targetsUpdated = updated || node.targetsUpdated 365 if updated { 366 node.graph.unsaved.Add(node.key) 367 } 368 } 369 370 // removeFromSources removes given key from the sources for the given relation. 371 func (node *node) removeFromSources(relation, label, key string) { 372 t, idx := node.sources.GetTargetForLabel(relation, label) 373 updated := t.MatchingKeys.Del(key) 374 if updated { 375 if t.MatchingKeys.Length() == 0 { 376 if idx < len(node.sources)-1 { 377 copy(node.sources[idx:], node.sources[idx+1:]) 378 } 379 node.sources = node.sources[0 : len(node.sources)-1] 380 } 381 node.sourcesUpdated = true 382 node.graph.unsaved.Add(node.key) 383 } 384 } 385 386 func expectedKey(target RelationTargetDef) (expKey string) { 387 if target.Key != "" { 388 return target.Key 389 } 390 for idx, prefix := range target.Selector.KeyPrefixes { 391 if idx > 0 { 392 expKey += " | " 393 } 394 expKey += prefix + "*" 395 } 396 return expKey 397 }