Skip to content

Commit 7d6292f

Browse files
codefromthecryptzirain
authored andcommitted
use syncmap
Signed-off-by: Adrian Cole <[email protected]>
1 parent d8d106e commit 7d6292f

File tree

3 files changed

+33
-46
lines changed

3 files changed

+33
-46
lines changed

internal/infrastructure/host/infra.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,7 @@ type Infra struct {
4646
EnvoyGateway *egv1a1.EnvoyGateway
4747

4848
// proxyContextMap store the context of each running proxy by its name for lifecycle management.
49-
proxyContextMap map[string]*proxyContext
50-
// mu protects proxyContextMap from concurrent access.
51-
mu sync.RWMutex
49+
proxyContextMap sync.Map
5250

5351
// TODO: remove this field once it supports the configurable homeDir
5452
sdsConfigPath string
@@ -82,7 +80,6 @@ func NewInfra(runnerCtx context.Context, cfg *config.Server, logger logging.Logg
8280
HomeDir: defaultHomeDir,
8381
Logger: logger,
8482
EnvoyGateway: cfg.EnvoyGateway,
85-
proxyContextMap: make(map[string]*proxyContext),
8683
sdsConfigPath: defaultLocalCertPathDir,
8784
defaultEnvoyImage: egv1a1.DefaultEnvoyProxyImage,
8885
Stdout: cfg.Stdout,

internal/infrastructure/host/proxy_infra.go

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ type proxyContext struct {
3434

3535
// Close implements the Manager interface.
3636
func (i *Infra) Close() error {
37-
i.mu.RLock()
38-
names := make([]string, 0, len(i.proxyContextMap))
39-
for name := range i.proxyContextMap {
40-
names = append(names, name)
41-
}
42-
i.mu.RUnlock()
37+
// Collect all proxy names first to avoid holding locks during stopEnvoy calls
38+
var names []string
39+
i.proxyContextMap.Range(func(key, value interface{}) bool {
40+
names = append(names, key.(string))
41+
return true
42+
})
4343

4444
for _, name := range names {
4545
i.stopEnvoy(name)
@@ -60,10 +60,7 @@ func (i *Infra) CreateOrUpdateProxyInfra(ctx context.Context, infra *ir.Infra) e
6060
proxyInfra := infra.GetProxyInfra()
6161
proxyName := utils.GetHashedName(proxyInfra.Name, 64)
6262
// Return directly if the proxy is running.
63-
i.mu.RLock()
64-
_, running := i.proxyContextMap[proxyName]
65-
i.mu.RUnlock()
66-
if running {
63+
if _, loaded := i.proxyContextMap.Load(proxyName); loaded {
6764
return nil
6865
}
6966

@@ -101,9 +98,7 @@ func (i *Infra) CreateOrUpdateProxyInfra(ctx context.Context, infra *ir.Infra) e
10198
func (i *Infra) runEnvoy(ctx context.Context, envoyVersion, name string, args []string) {
10299
pCtx, cancel := context.WithCancel(ctx)
103100
exit := make(chan struct{}, 1)
104-
i.mu.Lock()
105-
i.proxyContextMap[name] = &proxyContext{cancel: cancel, exit: exit}
106-
i.mu.Unlock()
101+
i.proxyContextMap.Store(name, &proxyContext{cancel: cancel, exit: exit})
107102
go func() {
108103
// Run blocks until pCtx is done or the process exits where the latter doesn't happen when
109104
// Envoy successfully starts up. So, this will not return until pCtx is done in practice.
@@ -136,18 +131,12 @@ func (i *Infra) DeleteProxyInfra(_ context.Context, infra *ir.Infra) error {
136131

137132
// stopEnvoy stops the Envoy process by its name. It will block until the process completely stopped.
138133
func (i *Infra) stopEnvoy(proxyName string) {
139-
i.mu.Lock()
140-
pCtx, ok := i.proxyContextMap[proxyName]
141-
i.mu.Unlock()
142-
134+
value, ok := i.proxyContextMap.LoadAndDelete(proxyName)
143135
if ok {
136+
pCtx := value.(*proxyContext)
144137
pCtx.cancel() // Cancel causes the Envoy process to exit.
145138
<-pCtx.exit // Wait for the Envoy process to completely exit.
146139
close(pCtx.exit) // Close the channel to avoid leaking.
147-
148-
i.mu.Lock()
149-
delete(i.proxyContextMap, proxyName)
150-
i.mu.Unlock()
151140
}
152141
}
153142

internal/infrastructure/host/proxy_infra_test.go

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,12 @@ func newMockInfra(t *testing.T, cfg *config.Server) *Infra {
4747
require.NoError(t, err)
4848

4949
infra := &Infra{
50-
HomeDir: homeDir,
51-
Logger: logging.DefaultLogger(io.Discard, egv1a1.LogLevelInfo),
52-
EnvoyGateway: cfg.EnvoyGateway,
53-
proxyContextMap: make(map[string]*proxyContext),
54-
sdsConfigPath: proxyDir,
55-
Stdout: io.Discard,
56-
Stderr: io.Discard,
50+
HomeDir: homeDir,
51+
Logger: logging.DefaultLogger(io.Discard, egv1a1.LogLevelInfo),
52+
EnvoyGateway: cfg.EnvoyGateway,
53+
sdsConfigPath: proxyDir,
54+
Stdout: io.Discard,
55+
Stderr: io.Discard,
5756
}
5857
return infra
5958
}
@@ -104,11 +103,10 @@ func TestInfra_runEnvoy_stopEnvoy(t *testing.T) {
104103
stdout := &bytes.Buffer{}
105104
stderr := &bytes.Buffer{}
106105
i := &Infra{
107-
proxyContextMap: make(map[string]*proxyContext),
108-
HomeDir: tmpdir,
109-
Logger: logging.DefaultLogger(stdout, egv1a1.LogLevelInfo),
110-
Stdout: stdout,
111-
Stderr: stderr,
106+
HomeDir: tmpdir,
107+
Logger: logging.DefaultLogger(stdout, egv1a1.LogLevelInfo),
108+
Stdout: stdout,
109+
Stderr: stderr,
112110
}
113111
// Ensures that run -> stop will successfully stop the envoy and we can
114112
// run it again without any issues.
@@ -118,9 +116,11 @@ func TestInfra_runEnvoy_stopEnvoy(t *testing.T) {
118116
"admin: {address: {socket_address: {address: '127.0.0.1', port_value: 9901}}}",
119117
}
120118
i.runEnvoy(t.Context(), "", "test", args)
121-
require.Len(t, i.proxyContextMap, 1)
119+
_, ok := i.proxyContextMap.Load("test")
120+
require.True(t, ok, "expected proxy context to be stored")
122121
i.stopEnvoy("test")
123-
require.Empty(t, i.proxyContextMap)
122+
_, ok = i.proxyContextMap.Load("test")
123+
require.False(t, ok, "expected proxy context to be removed")
124124
// If the cleanup didn't work, the error due to "address already in use" will be tried to be written to the nil logger,
125125
// which will panic.
126126
}
@@ -167,11 +167,10 @@ func TestInfra_runEnvoy_OutputRedirection(t *testing.T) {
167167
stderr := buffers[1]
168168

169169
i := &Infra{
170-
proxyContextMap: make(map[string]*proxyContext),
171-
HomeDir: tmpdir,
172-
Logger: logging.DefaultLogger(stdout, egv1a1.LogLevelInfo),
173-
Stdout: stdout,
174-
Stderr: stderr,
170+
HomeDir: tmpdir,
171+
Logger: logging.DefaultLogger(stdout, egv1a1.LogLevelInfo),
172+
Stdout: stdout,
173+
Stderr: stderr,
175174
}
176175

177176
// Run envoy with an invalid config to force it to write to stderr and exit quickly
@@ -181,15 +180,17 @@ func TestInfra_runEnvoy_OutputRedirection(t *testing.T) {
181180
}
182181

183182
i.runEnvoy(t.Context(), "", "test", args)
184-
require.Len(t, i.proxyContextMap, 1)
183+
_, ok := i.proxyContextMap.Load("test")
184+
require.True(t, ok, "expected proxy context to be stored")
185185

186186
// Wait a bit for envoy to fail
187187
require.Eventually(t, func() bool {
188188
return stderr.Len() > 0 || stdout.Len() > 0
189189
}, 5*time.Second, 100*time.Millisecond, "expected output to be written to buffers")
190190

191191
i.stopEnvoy("test")
192-
require.Empty(t, i.proxyContextMap)
192+
_, ok = i.proxyContextMap.Load("test")
193+
require.False(t, ok, "expected proxy context to be removed")
193194

194195
// Verify that output was captured in buffers (either stdout or stderr should have content)
195196
totalOutput := stdout.Len() + stderr.Len()

0 commit comments

Comments
 (0)