Skip to content

Commit bb74e15

Browse files
committed
Use sync once mutex to avoid race condition
- Fixes issue sideshow#58
1 parent 04f36d8 commit bb74e15

File tree

2 files changed

+22
-12
lines changed

2 files changed

+22
-12
lines changed

client_manager.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type ClientManager struct {
3434
cache map[[sha1.Size]byte]*list.Element
3535
ll *list.List
3636
mu sync.Mutex
37+
once sync.Once
3738
}
3839

3940
// NewClientManager returns a new ClientManager for prolonged, concurrent usage
@@ -60,11 +61,10 @@ func NewClientManager() *ClientManager {
6061
// Add adds a Client to the manager. You can use this to individually configure
6162
// Clients in the manager.
6263
func (m *ClientManager) Add(client *Client) {
63-
if m.cache == nil {
64-
m.initInternals()
65-
}
64+
m.initInternals()
6665
m.mu.Lock()
6766
defer m.mu.Unlock()
67+
6868
key := cacheKey(client.Certificate)
6969
now := time.Now()
7070
if ele, hit := m.cache[key]; hit {
@@ -88,11 +88,10 @@ func (m *ClientManager) Add(client *Client) {
8888
// the ClientManager's Factory function, store the result in the manager if
8989
// non-nil, and return it.
9090
func (m *ClientManager) Get(certificate tls.Certificate) *Client {
91-
if m.cache == nil {
92-
m.initInternals()
93-
}
91+
m.initInternals()
9492
m.mu.Lock()
9593
defer m.mu.Unlock()
94+
9695
key := cacheKey(certificate)
9796
now := time.Now()
9897
if ele, hit := m.cache[key]; hit {
@@ -130,9 +129,10 @@ func (m *ClientManager) Len() int {
130129
}
131130

132131
func (m *ClientManager) initInternals() {
133-
m.cache = map[[sha1.Size]byte]*list.Element{}
134-
m.ll = list.New()
135-
m.mu = sync.Mutex{}
132+
m.once.Do(func() {
133+
m.cache = map[[sha1.Size]byte]*list.Element{}
134+
m.ll = list.New()
135+
})
136136
}
137137

138138
func (m *ClientManager) removeOldest() {

client_manager_test.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"crypto/tls"
66
"reflect"
7+
"sync"
78
"testing"
89
"time"
910

@@ -35,14 +36,23 @@ func TestClientManagerGetWithoutNew(t *testing.T) {
3536
}
3637

3738
func TestClientManagerAddWithoutNew(t *testing.T) {
39+
wg := sync.WaitGroup{}
40+
3841
manager := apns2.ClientManager{
39-
MaxSize: 32,
42+
MaxSize: 1,
4043
MaxAge: 5 * time.Minute,
4144
Factory: apns2.NewClient,
4245
}
4346

44-
manager.Add(apns2.NewClient(mockCert()))
45-
assert.Equal(t, 1, manager.Len())
47+
for i := 0; i < 2; i++ {
48+
wg.Add(1)
49+
go func() {
50+
manager.Add(apns2.NewClient(mockCert()))
51+
assert.Equal(t, 1, manager.Len())
52+
wg.Done()
53+
}()
54+
}
55+
wg.Wait()
4656
}
4757

4858
func TestClientManagerLenWithoutNew(t *testing.T) {

0 commit comments

Comments
 (0)