TopologyAwareHints: Take lock in HasPopulatedHints

Prevent potential concurrent map access by taking a lock before reading the
topology cache's hintsPopulatedByService map.

* staging/src/k8s.io/endpointslice/topologycache/topologycache.go
(setHintsLocked, hasPopulatedHintsLocked): New helper functions.  These are
the same as the existing SetHints and HasPopulatedHints methods except that
these helpers assume that a lock is already held.
(SetHints): Use setHintsLocked.
(HasPopulatedHints): Take a lock and use hasPopulatedHintsLocked.
(AddHints): Take a lock and use setHintsLocked and hasPopulatedHintsLocked.
* staging/src/k8s.io/endpointslice/topologycache/topologycache_test.go
(TestTopologyCacheRace): Add a goroutine that calls HasPopulatedHints.
This commit is contained in:
Miciah Masters 2023-05-22 17:24:25 -04:00 committed by Miciah Dashiel Butler Masters
parent 6d83e22ba4
commit 43f8ccfcca
2 changed files with 18 additions and 2 deletions

View File

@ -153,8 +153,10 @@ func (t *TopologyCache) AddHints(logger klog.Logger, si *SliceInfo) ([]*discover
return slicesToCreate, slicesToUpdate, events
}
hintsEnabled := t.hintsPopulatedByService.Has(si.ServiceKey)
t.SetHints(si.ServiceKey, si.AddressType, allocatedHintsByZone)
t.lock.Lock()
defer t.lock.Unlock()
hintsEnabled := t.hasPopulatedHintsLocked(si.ServiceKey)
t.setHintsLocked(si.ServiceKey, si.AddressType, allocatedHintsByZone)
// if hints were not enabled before, we publish an event to indicate we enabled them.
if !hintsEnabled {
@ -174,6 +176,10 @@ func (t *TopologyCache) SetHints(serviceKey string, addrType discovery.AddressTy
t.lock.Lock()
defer t.lock.Unlock()
t.setHintsLocked(serviceKey, addrType, allocatedHintsByZone)
}
func (t *TopologyCache) setHintsLocked(serviceKey string, addrType discovery.AddressType, allocatedHintsByZone EndpointZoneInfo) {
_, ok := t.endpointsByService[serviceKey]
if !ok {
t.endpointsByService[serviceKey] = map[discovery.AddressType]EndpointZoneInfo{}
@ -262,6 +268,13 @@ func (t *TopologyCache) SetNodes(logger klog.Logger, nodes []*v1.Node) {
// HasPopulatedHints checks whether there are populated hints for a given service in the cache.
func (t *TopologyCache) HasPopulatedHints(serviceKey string) bool {
t.lock.Lock()
defer t.lock.Unlock()
return t.hasPopulatedHintsLocked(serviceKey)
}
func (t *TopologyCache) hasPopulatedHintsLocked(serviceKey string) bool {
return t.hintsPopulatedByService.Has(serviceKey)
}

View File

@ -690,6 +690,9 @@ func TestTopologyCacheRace(t *testing.T) {
go func() {
cache.AddHints(logger, sliceInfo)
}()
go func() {
cache.HasPopulatedHints(sliceInfo.ServiceKey)
}()
}
// Test Helpers