istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/model/addressmap.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 model
    16  
    17  import (
    18  	"sync"
    19  
    20  	"istio.io/istio/pkg/cluster"
    21  )
    22  
    23  // AddressMap provides a thread-safe mapping of addresses for each Kubernetes cluster.
    24  type AddressMap struct {
    25  	// Addresses hold the underlying map. Most code should only access this through the available methods.
    26  	// Should only be used by tests and construction/initialization logic, where there is no concern
    27  	// for race conditions.
    28  	Addresses map[cluster.ID][]string
    29  
    30  	// NOTE: The copystructure library is not able to copy unexported fields, so the mutex will not be copied.
    31  	mutex sync.RWMutex
    32  }
    33  
    34  func (m *AddressMap) Len() int {
    35  	if m == nil {
    36  		return 0
    37  	}
    38  	m.mutex.RLock()
    39  	defer m.mutex.RUnlock()
    40  
    41  	return len(m.Addresses)
    42  }
    43  
    44  func (m *AddressMap) DeepCopy() *AddressMap {
    45  	if m == nil {
    46  		return nil
    47  	}
    48  	return &AddressMap{
    49  		Addresses: m.GetAddresses(),
    50  	}
    51  }
    52  
    53  // GetAddresses returns the mapping of clusters to addresses.
    54  func (m *AddressMap) GetAddresses() map[cluster.ID][]string {
    55  	if m == nil {
    56  		return nil
    57  	}
    58  
    59  	m.mutex.RLock()
    60  	defer m.mutex.RUnlock()
    61  
    62  	if m.Addresses == nil {
    63  		return nil
    64  	}
    65  
    66  	out := make(map[cluster.ID][]string)
    67  	for k, v := range m.Addresses {
    68  		if v == nil {
    69  			out[k] = nil
    70  		} else {
    71  			out[k] = append([]string{}, v...)
    72  		}
    73  	}
    74  	return out
    75  }
    76  
    77  // SetAddresses sets the addresses per cluster.
    78  func (m *AddressMap) SetAddresses(addrs map[cluster.ID][]string) {
    79  	if len(addrs) == 0 {
    80  		addrs = nil
    81  	}
    82  
    83  	m.mutex.Lock()
    84  	m.Addresses = addrs
    85  	m.mutex.Unlock()
    86  }
    87  
    88  func (m *AddressMap) GetAddressesFor(c cluster.ID) []string {
    89  	if m == nil {
    90  		return nil
    91  	}
    92  
    93  	m.mutex.RLock()
    94  	defer m.mutex.RUnlock()
    95  
    96  	if m.Addresses == nil {
    97  		return nil
    98  	}
    99  
   100  	// Copy the Addresses array.
   101  	return append([]string{}, m.Addresses[c]...)
   102  }
   103  
   104  func (m *AddressMap) SetAddressesFor(c cluster.ID, addresses []string) *AddressMap {
   105  	m.mutex.Lock()
   106  	defer m.mutex.Unlock()
   107  
   108  	if len(addresses) == 0 {
   109  		// Setting an empty array for the cluster. Remove the entry for the cluster if it exists.
   110  		if m.Addresses != nil {
   111  			delete(m.Addresses, c)
   112  
   113  			// Delete the map if there's nothing left.
   114  			if len(m.Addresses) == 0 {
   115  				m.Addresses = nil
   116  			}
   117  		}
   118  	} else {
   119  		// Create the map if it doesn't already exist.
   120  		if m.Addresses == nil {
   121  			m.Addresses = make(map[cluster.ID][]string)
   122  		}
   123  		m.Addresses[c] = addresses
   124  	}
   125  	return m
   126  }
   127  
   128  func (m *AddressMap) AddAddressesFor(c cluster.ID, addresses []string) *AddressMap {
   129  	if len(addresses) == 0 {
   130  		return m
   131  	}
   132  
   133  	m.mutex.Lock()
   134  	defer m.mutex.Unlock()
   135  
   136  	// Create the map if nil.
   137  	if m.Addresses == nil {
   138  		m.Addresses = make(map[cluster.ID][]string)
   139  	}
   140  
   141  	m.Addresses[c] = append(m.Addresses[c], addresses...)
   142  	return m
   143  }
   144  
   145  func (m *AddressMap) ForEach(fn func(c cluster.ID, addresses []string)) {
   146  	if m == nil {
   147  		return
   148  	}
   149  
   150  	m.mutex.RLock()
   151  	defer m.mutex.RUnlock()
   152  
   153  	if m.Addresses == nil {
   154  		return
   155  	}
   156  
   157  	for c, addresses := range m.Addresses {
   158  		fn(c, addresses)
   159  	}
   160  }