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  }