go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/internal/utils/dependencies.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 utils 16 17 import ( 18 "sort" 19 ) 20 21 // DependsOn returns true if k1 depends on k2 based on dependencies from <deps>. 22 func DependsOn(k1, k2 string, deps map[string]KeySet, visited KeySet) bool { 23 // check direct dependencies 24 k1Deps := deps[k1] 25 if depends := k1Deps.Has(k2); depends { 26 return true 27 } 28 29 // continue transitively 30 visited.Add(k1) 31 for _, dep := range k1Deps.Iterate() { 32 if wasVisited := visited.Has(dep); wasVisited { 33 continue 34 } 35 if DependsOn(dep, k2, deps, visited) { 36 return true 37 } 38 } 39 return false 40 } 41 42 // TopologicalOrder orders keys topologically by Kahn's algorithm to respect 43 // the given dependencies. 44 // deps = map{ key -> <set of keys the given key depends on> } 45 func TopologicalOrder(keys KeySet, deps map[string]KeySet, depFirst bool, handleCycle bool) (sorted []string) { 46 // copy input arguments so that they are not returned to the caller changed 47 remains := keys.CopyOnWrite() 48 remainsDeps := make(map[string]KeySet) 49 for key, keyDeps := range deps { 50 if !keys.Has(key) { 51 continue 52 } 53 remainsDeps[key] = keyDeps.CopyOnWrite() 54 remainsDeps[key].Intersect(keys) 55 } 56 57 // Kahn's algorithm (except for the cycle handling part): 58 for remains.Length() > 0 { 59 // find candidate keys - keys that could follow in the order 60 var candidates []string 61 for _, key := range remains.Iterate() { 62 // if depFirst, select keys that do not depend on anything in the remaining set 63 candidate := depFirst && remainsDeps[key].Length() == 0 64 if !depFirst { 65 candidate = true 66 // is there any other key depending on this one? 67 for _, key2Deps := range remainsDeps { 68 if key2Deps.Has(key) { 69 candidate = false 70 break 71 } 72 } 73 } 74 if candidate { 75 candidates = append(candidates, key) 76 } 77 } 78 79 // handle cycles 80 var cycle bool 81 if len(candidates) == 0 { 82 cycle = true 83 if !handleCycle { 84 panic("Dependency cycle!") 85 } 86 // select keys that depend on themselves 87 for _, key := range remains.Iterate() { 88 if DependsOn(key, key, deps, NewMapBasedKeySet()) { 89 candidates = append(candidates, key) 90 } 91 } 92 } 93 94 // to make the algorithm deterministic (for simplified testing), 95 // order the candidates 96 sort.Strings(candidates) 97 98 // in case of cycle output all the keys from the cycle, otherwise just the first candidate 99 var selected []string 100 if cycle { 101 selected = candidates 102 } else { 103 selected = append(selected, candidates[0]) 104 } 105 sorted = append(sorted, selected...) 106 107 // remove selected key(s) from the set of remaining keys 108 for _, key := range selected { 109 remains.Del(key) 110 delete(remainsDeps, key) 111 // remove dependency edges going to this key 112 for _, key2Deps := range remainsDeps { 113 key2Deps.Del(key) 114 } 115 } 116 } 117 return sorted 118 }