blob: c839a196bb4bfe2635eb798d3ff9d8280367ac18 [file] [log] [blame]
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package workloadinstances
import (
"sync"
)
import (
"github.com/apache/dubbo-go-pixiu/pilot/pkg/model"
)
// Index reprensents an index over workload instances from workload entries.
//
// Indexes are thread-safe.
type Index interface {
// Insert adds/updates given workload instance to the index.
//
// Returns previous value in the index, or nil otherwise.
Insert(*model.WorkloadInstance) *model.WorkloadInstance
// Delete removes given workload instance from the index.
//
// Returns value removed from the index, or nil otherwise.
Delete(*model.WorkloadInstance) *model.WorkloadInstance
// GetByIP returns a list of all workload instances associated with a
// given IP address. The list is ordered by namespace/name.
//
// There are several use cases where multiple workload instances might
// have the same IP address:
// 1) there are multiple Istio Proxies running on a single host, e.g.
// in 'router' mode or even in 'sidecar' mode.
// 2) workload instances have the same IP but different networks
GetByIP(string) []*model.WorkloadInstance
// Empty returns whether the index is empty.
Empty() bool
// ForEach iterates over all workload instances in the index.
ForEach(func(*model.WorkloadInstance))
}
// indexKey returns index key for a given workload instance.
func indexKey(wi *model.WorkloadInstance) string {
return wi.Namespace + "/" + wi.Name
}
// NewIndex returns a new Index instance.
func NewIndex() Index {
return &index{
keyFunc: indexKey,
keyToInstance: make(map[string]*model.WorkloadInstance),
ipToKeys: make(MultiValueMap),
}
}
// index implements Index.
type index struct {
mu sync.RWMutex
// key function
keyFunc func(*model.WorkloadInstance) string
// map of namespace/name -> workload instance
keyToInstance map[string]*model.WorkloadInstance
// map of ip -> set of namespace/name
ipToKeys MultiValueMap
}
// Insert implements Index.
func (i *index) Insert(wi *model.WorkloadInstance) *model.WorkloadInstance {
i.mu.Lock()
defer i.mu.Unlock()
key := i.keyFunc(wi)
// Check to see if the workload entry changed. If it did, clear the old entry
previous := i.keyToInstance[key]
if previous != nil && previous.Endpoint.Address != wi.Endpoint.Address {
i.ipToKeys.Delete(previous.Endpoint.Address, key)
}
i.keyToInstance[key] = wi
i.ipToKeys.Insert(wi.Endpoint.Address, key)
return previous
}
// Delete implements Index.
func (i *index) Delete(wi *model.WorkloadInstance) *model.WorkloadInstance {
i.mu.Lock()
defer i.mu.Unlock()
key := i.keyFunc(wi)
previous := i.keyToInstance[key]
if previous != nil {
i.ipToKeys.Delete(previous.Endpoint.Address, key)
}
i.ipToKeys.Delete(wi.Endpoint.Address, key)
delete(i.keyToInstance, key)
return previous
}
// GetByIP implements Index.
func (i *index) GetByIP(ip string) []*model.WorkloadInstance {
i.mu.RLock()
defer i.mu.RUnlock()
keys := i.ipToKeys[ip]
if len(keys) == 0 {
return nil
}
instances := make([]*model.WorkloadInstance, 0, len(keys))
for _, key := range keys.SortedList() {
if instance, exists := i.keyToInstance[key]; exists {
instances = append(instances, instance)
}
}
return instances
}
// Empty implements Index.
func (i *index) Empty() bool {
i.mu.RLock()
defer i.mu.RUnlock()
return len(i.keyToInstance) == 0
}
// ForEach iterates over all workload instances in the index.
func (i *index) ForEach(fn func(*model.WorkloadInstance)) {
i.mu.RLock()
defer i.mu.RUnlock()
for _, instance := range i.keyToInstance {
fn(instance)
}
}