istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/serviceregistry/util/workloadinstances/index.go (about) 1 // Copyright Istio Authors 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 workloadinstances 16 17 import ( 18 "sync" 19 20 "istio.io/istio/pilot/pkg/model" 21 "istio.io/istio/pkg/util/sets" 22 ) 23 24 // Index reprensents an index over workload instances from workload entries. 25 // 26 // Indexes are thread-safe. 27 type Index interface { 28 // Insert adds/updates given workload instance to the index. 29 // 30 // Returns previous value in the index, or nil otherwise. 31 Insert(*model.WorkloadInstance) *model.WorkloadInstance 32 // Delete removes given workload instance from the index. 33 // 34 // Returns value removed from the index, or nil otherwise. 35 Delete(*model.WorkloadInstance) *model.WorkloadInstance 36 // GetByIP returns a list of all workload instances associated with a 37 // given IP address. The list is ordered by namespace/name. 38 // 39 // There are several use cases where multiple workload instances might 40 // have the same IP address: 41 // 1) there are multiple Istio Proxies running on a single host, e.g. 42 // in 'router' mode or even in 'sidecar' mode. 43 // 2) workload instances have the same IP but different networks 44 GetByIP(string) []*model.WorkloadInstance 45 // Empty returns whether the index is empty. 46 Empty() bool 47 // ForEach iterates over all workload instances in the index. 48 ForEach(func(*model.WorkloadInstance)) 49 } 50 51 // indexKey returns index key for a given workload instance. 52 func indexKey(wi *model.WorkloadInstance) string { 53 return wi.Namespace + "/" + wi.Name 54 } 55 56 // NewIndex returns a new Index instance. 57 func NewIndex() Index { 58 return &index{ 59 keyFunc: indexKey, 60 keyToInstance: make(map[string]*model.WorkloadInstance), 61 ipToKeys: make(MultiValueMap), 62 } 63 } 64 65 // index implements Index. 66 type index struct { 67 mu sync.RWMutex 68 // key function 69 keyFunc func(*model.WorkloadInstance) string 70 // map of namespace/name -> workload instance 71 keyToInstance map[string]*model.WorkloadInstance 72 // map of ip -> set of namespace/name 73 ipToKeys MultiValueMap 74 } 75 76 // Insert implements Index. 77 func (i *index) Insert(wi *model.WorkloadInstance) *model.WorkloadInstance { 78 i.mu.Lock() 79 defer i.mu.Unlock() 80 81 key := i.keyFunc(wi) 82 // Check to see if the workload entry changed. If it did, clear the old entry 83 previous := i.keyToInstance[key] 84 if previous != nil && previous.Endpoint.Address != wi.Endpoint.Address { 85 i.ipToKeys.Delete(previous.Endpoint.Address, key) 86 } 87 i.keyToInstance[key] = wi 88 if wi.Endpoint.Address != "" { 89 i.ipToKeys.Insert(wi.Endpoint.Address, key) 90 } 91 return previous 92 } 93 94 // Delete implements Index. 95 func (i *index) Delete(wi *model.WorkloadInstance) *model.WorkloadInstance { 96 i.mu.Lock() 97 defer i.mu.Unlock() 98 99 key := i.keyFunc(wi) 100 previous := i.keyToInstance[key] 101 if previous != nil { 102 i.ipToKeys.Delete(previous.Endpoint.Address, key) 103 } 104 i.ipToKeys.Delete(wi.Endpoint.Address, key) 105 delete(i.keyToInstance, key) 106 return previous 107 } 108 109 // GetByIP implements Index. 110 func (i *index) GetByIP(ip string) []*model.WorkloadInstance { 111 i.mu.RLock() 112 defer i.mu.RUnlock() 113 114 keys := i.ipToKeys[ip] 115 if len(keys) == 0 { 116 return nil 117 } 118 instances := make([]*model.WorkloadInstance, 0, len(keys)) 119 for _, key := range sets.SortedList(keys) { 120 if instance, exists := i.keyToInstance[key]; exists { 121 instances = append(instances, instance) 122 } 123 } 124 return instances 125 } 126 127 // Empty implements Index. 128 func (i *index) Empty() bool { 129 i.mu.RLock() 130 defer i.mu.RUnlock() 131 132 return len(i.keyToInstance) == 0 133 } 134 135 // ForEach iterates over all workload instances in the index. 136 func (i *index) ForEach(fn func(*model.WorkloadInstance)) { 137 i.mu.RLock() 138 defer i.mu.RUnlock() 139 140 for _, instance := range i.keyToInstance { 141 fn(instance) 142 } 143 }