go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/internal/graph/graph_api.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 "bytes" 19 "fmt" 20 "sort" 21 "time" 22 23 "go.ligato.io/cn-infra/v2/idxmap" 24 "google.golang.org/protobuf/proto" 25 26 . "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api" 27 "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/internal/utils" 28 ) 29 30 // Graph is an in-memory graph representation of key-value pairs and their 31 // relations, where nodes are kv-pairs and each relation is a separate set of 32 // direct labeled edges. 33 // 34 // The graph furthermore allows to associate metadata and flags (idx/name:value 35 // pairs) with every node. It is possible to register instances of NamedMapping, 36 // each for a different set of selected nodes, and the graph will keep them 37 // up-to-date with the latest value-label->metadata associations. 38 // 39 // The graph provides various getter method, for example it is possible to select 40 // a set of nodes using a key selector and/or a flag selector. 41 // As for editing, Graph allows to either write in-place (immediate effect) 42 // or to prepare new changes and then save them later or let them get discarded 43 // by GC. 44 // 45 // The graph supports multiple-readers single-writer access, i.e. it is assumed 46 // there is no write-concurrency. 47 // 48 // Last but not least, the graph maintains a history of revisions for all nodes 49 // that have ever existed. The history of changes and a graph snapshot from 50 // a selected moment in time are exposed via ReadAccess interface. 51 type Graph interface { 52 // Read returns a graph handle for read-only access. 53 // The graph supports multiple concurrent readers. 54 // Release eventually using Release() method. 55 Read() ReadAccess // acquires R-lock 56 57 // Write returns a graph handle for read-write access. 58 // The graph supports at most one writer at a time - i.e. it is assumed 59 // there is no write-concurrency. 60 // If <inPlace> is enabled, the changes are applied with immediate effect, 61 // otherwise they are propagated to the graph using Save(). 62 // In-place Write handle holds write lock, therefore reading is blocked until 63 // the handle is released. 64 // If <record> is true, the changes will be recorded once the handle is 65 // released. 66 // Release eventually using Release() method. 67 Write(inPlace, record bool) RWAccess 68 } 69 70 // ReadAccess lists operations provided by the read-only graph handle. 71 type ReadAccess interface { 72 // GetMetadataMap returns registered metadata map. 73 GetMetadataMap(mapName string) idxmap.NamedMapping 74 75 // GetKeys returns sorted keys. 76 GetKeys() []string 77 78 // GetNode returns node with the given key or nil if the key is unused. 79 GetNode(key string) Node 80 81 // GetNodes returns a set of nodes matching the key selector (can be nil) 82 // and every provided flag selector. 83 GetNodes(keySelector KeySelector, flagSelectors ...FlagSelector) []Node 84 85 // GetFlagStats returns stats for a given flag. 86 GetFlagStats(flagIndex int, filter KeySelector) FlagStats 87 88 // GetNodeTimeline returns timeline of all node revisions, ordered from 89 // the oldest to the newest. 90 GetNodeTimeline(key string) []*RecordedNode 91 92 // GetSnapshot returns the snapshot of the graph at a given time. 93 GetSnapshot(time time.Time) []*RecordedNode 94 95 // Dump returns a human-readable string representation of the current graph 96 // content for debugging purposes. 97 Dump() string 98 99 // Release releases the graph handle (both Read() & Write() should end with 100 // release). 101 // For reader, the method releases R-lock. 102 // For in-place writer, the method releases W-lock. 103 Release() 104 105 // ValidateEdges checks if targets and sources of all nodes correspond with 106 // each other. 107 // Use only for UTs, debugging, etc. 108 ValidateEdges() error 109 } 110 111 // RWAccess lists operations provided by the read-write graph handle. 112 type RWAccess interface { 113 ReadAccess 114 115 // RegisterMetadataMap registers new metadata map for value-label->metadata 116 // associations of selected node. 117 RegisterMetadataMap(mapName string, mapping idxmap.NamedMappingRW) 118 119 // SetNode creates new node or returns read-write handle to an existing node. 120 // If in-place writing is disabled, the changes are propagated to the graph 121 // only after Save() is called. 122 SetNode(key string) NodeRW 123 124 // DeleteNode deletes node with the given key. 125 // Returns true if the node really existed before the operation. 126 DeleteNode(key string) bool 127 128 // Save propagates all changes to the graph. 129 // Use for **not-in-place** writing. 130 // NOOP if no changes performed, acquires RW-lock for the time of the operation 131 Save() 132 } 133 134 // TargetIterator is a callback applied on every target. 135 // For each label it will be called n+1 times, where n is the number of targets 136 // available for the given label and the extra call will be made with nil target. 137 type TargetIterator func(target Node, label string) (skipLabel, abort bool) 138 139 // Node is a read-only handle to a single graph node. 140 type Node interface { 141 // GetKey returns the key associated with the node. 142 GetKey() string 143 144 // GetLabel returns the label associated with this node. 145 GetLabel() string 146 147 // GetValue returns the value associated with the node. 148 GetValue() proto.Message 149 150 // GetFlag returns reference to the given flag or nil if the node doesn't have 151 // this flag associated. 152 GetFlag(flagIndex int) Flag 153 154 // GetMetadata returns the value metadata associated with the node. 155 GetMetadata() interface{} 156 157 // GetTargets returns a set of nodes, indexed by relation labels, that the 158 // edges of the given relation points to. 159 GetTargets(relation string) RuntimeTargets 160 161 // IterTargets allows to iterate over the set of nodes that the edges of the given 162 // relation points to. 163 IterTargets(relation string, callback TargetIterator) 164 165 // GetSources returns edges pointing to this node in the reverse 166 // orientation. 167 GetSources(relation string) RuntimeTargets 168 } 169 170 // NodeRW is a read-write handle to a single graph node. 171 type NodeRW interface { 172 Node 173 174 // SetLabel associates given label with this node. 175 SetLabel(label string) 176 177 // SetValue associates given value with this node. 178 SetValue(value proto.Message) 179 180 // SetFlags associates given flag with this node. 181 SetFlags(flags ...Flag) 182 183 // DelFlags removes given flags from this node. 184 DelFlags(flagIndexes ...int) 185 186 // SetMetadataMap chooses metadata map to be used to store the association 187 // between this node's value label and metadata. 188 SetMetadataMap(mapName string) 189 190 // SetMetadata associates given value metadata with this node. 191 SetMetadata(metadata interface{}) 192 193 // SetTargets updates definitions of all edges pointing from this node. 194 SetTargets(targets []RelationTargetDef) 195 } 196 197 // Flag is a (index+name):value pair. 198 type Flag interface { 199 // GetIndex should return unique index among all defined flags, starting 200 // from 0. 201 GetIndex() int 202 203 // GetName should return name of the flag. 204 GetName() string 205 206 // GetValue return the associated value. Can be empty. 207 GetValue() string 208 } 209 210 // FlagSelector is used to select node with(out) given flags assigned. 211 // 212 // Flag value=="" => any value 213 type FlagSelector struct { 214 with bool 215 flags []Flag 216 } 217 218 // WithFlags creates flag selector selecting nodes that have all the listed flags 219 // assigned. 220 func WithFlags(flags ...Flag) FlagSelector { 221 return FlagSelector{with: true, flags: flags} 222 } 223 224 // WithoutFlags creates flag selector selecting nodes that do not have 225 // any of the listed flags assigned. 226 func WithoutFlags(flags ...Flag) FlagSelector { 227 return FlagSelector{flags: flags} 228 } 229 230 // RelationTargetDef is a definition of a relation between a source node and a set 231 // of target nodes. 232 type RelationTargetDef struct { 233 // Relation name. 234 Relation string 235 236 // Label for the edge. 237 Label string // mandatory, unique for a given (source, relation) 238 239 // Either Key or Selector should be defined: 240 241 // Key of the target node. 242 Key string 243 244 // Selector selecting a set of target nodes. 245 Selector TargetSelector 246 } 247 248 // Compare compares two relation target definitions (with the exception of KeySelector-s). 249 func (t RelationTargetDef) Compare(t2 RelationTargetDef) (equal bool, order int) { 250 if t.Relation < t2.Relation { 251 return false, -1 252 } 253 if t.Relation > t2.Relation { 254 return false, 1 255 } 256 if t.Label < t2.Label { 257 return false, -1 258 } 259 if t.Label > t2.Label { 260 return false, 1 261 } 262 if t.Key != t2.Key { 263 return false, 0 264 } 265 if len(t.Selector.KeyPrefixes) != len(t2.Selector.KeyPrefixes) { 266 return false, 0 267 } 268 for i := 0; i < len(t.Selector.KeyPrefixes); i++ { 269 if t.Selector.KeyPrefixes[i] != t2.Selector.KeyPrefixes[i] { 270 return false, 0 271 } 272 } 273 return true, 0 274 } 275 276 // WithKeySelector returns true if the target is defined with key selector. 277 func (t RelationTargetDef) WithKeySelector() bool { 278 return t.Key == "" && t.Selector.KeySelector != nil 279 } 280 281 // Singleton returns true if the target matches at most one key. 282 func (t RelationTargetDef) Singleton() bool { 283 return t.Key != "" || (t.Selector.KeySelector == nil && len(t.Selector.KeyPrefixes) == 0) 284 } 285 286 // TargetSelector allows to dynamically select a set of target nodes. 287 // The selections of KeyPrefixes and KeySelector are **intersected**. 288 type TargetSelector struct { 289 // KeyPrefixes is a list of key prefixes, each selecting a subset of target 290 // nodes, which are then combined together - i.e. **union** is computed. 291 KeyPrefixes []string 292 293 // KeySelector allows to dynamically select target nodes. 294 KeySelector KeySelector 295 } 296 297 // Target nodes - not referenced directly, instead via their keys (suitable 298 // for recording). 299 type Target struct { 300 Relation string 301 Label string 302 ExpectedKey string // empty if Selector is used instead 303 MatchingKeys utils.KeySet 304 } 305 306 // Targets is a slice of all targets of a single node, sorted by relation+label 307 // (in this order). 308 type Targets []Target 309 310 // String returns human-readable string representation of Targets. 311 func (ts Targets) String() string { 312 var ( 313 idx int 314 str string 315 relation string 316 ) 317 if len(ts) > 0 { 318 relation = ts[0].Relation 319 str += relation + ":" 320 } 321 str += "{" 322 for _, target := range ts { 323 if target.Relation != relation { 324 relation = target.Relation 325 str += "} " + relation + ":{" 326 idx = 0 327 } 328 if idx > 0 { 329 str += ", " 330 } 331 str += fmt.Sprintf("%s->%s", target.Label, target.MatchingKeys.String()) 332 idx++ 333 } 334 str += "}" 335 return str 336 } 337 338 // RelationBegin returns index where targets for a given relation start 339 // in the array, or len(ts) if there are none. 340 func (ts Targets) RelationBegin(relation string) int { 341 idx := ts.lookupIdx(relation, "") 342 if idx < len(ts) && ts[idx].Relation == relation { 343 return idx 344 } 345 return len(ts) 346 } 347 348 // GetTargetForLabel returns reference(+index) to target with the given 349 // relation+label. 350 func (ts Targets) GetTargetForLabel(relation, label string) (t *Target, idx int) { 351 idx = ts.lookupIdx(relation, label) 352 if idx < len(ts) && 353 ts[idx].Relation == relation && ts[idx].Label == label { 354 return &ts[idx], idx 355 } 356 return nil, idx 357 } 358 359 // lookupIdx returns index where target for the given (relation,label) pair should 360 // be stored in the array. 361 func (ts Targets) lookupIdx(relation, label string) int { 362 idx := sort.Search(len(ts), 363 func(i int) bool { 364 if relation < ts[i].Relation { 365 return true 366 } 367 if relation == ts[i].Relation && label <= ts[i].Label { 368 return true 369 } 370 return false 371 }) 372 return idx 373 } 374 375 // copy returns deep copy of targets (key sets deep copied on write). 376 func (ts Targets) copy() Targets { 377 tCopy := make(Targets, len(ts)) 378 copy(tCopy, ts) 379 for i := range tCopy { 380 tCopy[i].MatchingKeys = ts[i].MatchingKeys.CopyOnWrite() 381 } 382 return tCopy 383 } 384 385 // RuntimeTarget, unlike Target, contains direct runtime references pointing 386 // to instances of target nodes (suitable for runtime processing but not for 387 // recording). 388 type RuntimeTarget struct { 389 Label string 390 Nodes []Node 391 } 392 393 // RuntimeTargets is a slice of single-relation (runtime reference-based) 394 // targets, grouped by labels. 395 type RuntimeTargets []RuntimeTarget 396 397 // GetTargetForLabel returns target (single node or a set of nodes) for 398 // the given label. 399 // Linear complexity is OK, it is used only in UTs. 400 func (rt RuntimeTargets) GetTargetForLabel(label string) *RuntimeTarget { 401 for idx := range rt { 402 if rt[idx].Label == label { 403 return &rt[idx] 404 } 405 } 406 return nil 407 } 408 409 // RecordedNode saves all attributes of a single node revision. 410 type RecordedNode struct { 411 Since time.Time 412 Until time.Time 413 Key string 414 Label string 415 Value proto.Message 416 Flags RecordedFlags 417 MetadataFields map[string][]string // field name -> values 418 Targets Targets 419 TargetUpdateOnly bool // true if only runtime Targets have changed since the last rev 420 } 421 422 // GetFlag returns reference to the given flag or nil if the node didn't have 423 // this flag associated at the time when it was recorded. 424 func (node *RecordedNode) GetFlag(flagIndex int) Flag { 425 return node.Flags.GetFlag(flagIndex) 426 } 427 428 // RecordedFlags is a record of assigned flags at a given time. 429 type RecordedFlags struct { 430 Flags [maxFlags]Flag 431 } 432 433 // MarshalJSON marshalls recorded flags into JSON. 434 func (rf RecordedFlags) MarshalJSON() ([]byte, error) { 435 buffer := bytes.NewBufferString("{") 436 first := true 437 for _, flag := range rf.Flags { 438 if flag == nil { 439 continue 440 } 441 if !first { 442 buffer.WriteString(",") 443 } 444 first = false 445 buffer.WriteString(fmt.Sprintf("\"%s\":\"%s\"", flag.GetName(), flag.GetValue())) 446 } 447 buffer.WriteString("}") 448 return buffer.Bytes(), nil 449 } 450 451 // GetFlag returns reference to the given flag or nil if the node hasn't had 452 // this flag associated at the given time. 453 func (rf RecordedFlags) GetFlag(flagIndex int) Flag { 454 return rf.Flags[flagIndex] 455 } 456 457 // FlagStats is a summary of the usage for a given flag. 458 type FlagStats struct { 459 TotalCount uint // number of revisions with the given flag assigned 460 PerValueCount map[string]uint // number of revisions with the given flag having the given value 461 }