Skip to content

Commit 55de623

Browse files
committed
nsqlookupd: fix write lock starvation
1 parent 5b67f58 commit 55de623

File tree

2 files changed

+52
-44
lines changed

2 files changed

+52
-44
lines changed

nsqlookupd/http.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,9 @@ func (s *httpServer) doDebug(w http.ResponseWriter, req *http.Request, ps httpro
308308
defer s.ctx.nsqlookupd.DB.RUnlock()
309309

310310
data := make(map[string][]map[string]interface{})
311-
for r, producers := range s.ctx.nsqlookupd.DB.registrationMap {
311+
s.ctx.nsqlookupd.DB.registrationMap.Range(func(k, v interface{}) bool {
312+
producers := v.(ProducerMap)
313+
r := k.(Registration)
312314
key := r.Category + ":" + r.Key + ":" + r.SubKey
313315
for _, p := range producers {
314316
m := map[string]interface{}{
@@ -324,7 +326,8 @@ func (s *httpServer) doDebug(w http.ResponseWriter, req *http.Request, ps httpro
324326
}
325327
data[key] = append(data[key], m)
326328
}
327-
}
329+
return true
330+
})
328331

329332
return data, nil
330333
}

nsqlookupd/registration_db.go

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
type RegistrationDB struct {
1111
sync.RWMutex
12-
registrationMap map[Registration]ProducerMap
12+
registrationMap *sync.Map
1313
}
1414

1515
type Registration struct {
@@ -54,119 +54,124 @@ func (p *Producer) IsTombstoned(lifetime time.Duration) bool {
5454

5555
func NewRegistrationDB() *RegistrationDB {
5656
return &RegistrationDB{
57-
registrationMap: make(map[Registration]ProducerMap),
57+
registrationMap: &sync.Map{},
5858
}
5959
}
6060

6161
// add a registration key
6262
func (r *RegistrationDB) AddRegistration(k Registration) {
63-
r.Lock()
64-
defer r.Unlock()
65-
_, ok := r.registrationMap[k]
66-
if !ok {
67-
r.registrationMap[k] = make(map[string]*Producer)
68-
}
63+
r.registrationMap.LoadOrStore(k, make(ProducerMap))
6964
}
7065

7166
// add a producer to a registration
7267
func (r *RegistrationDB) AddProducer(k Registration, p *Producer) bool {
7368
r.Lock()
7469
defer r.Unlock()
75-
_, ok := r.registrationMap[k]
76-
if !ok {
77-
r.registrationMap[k] = make(map[string]*Producer)
78-
}
79-
producers := r.registrationMap[k]
70+
val, _ := r.registrationMap.LoadOrStore(k, make(ProducerMap))
71+
producers := val.(ProducerMap)
8072
_, found := producers[p.peerInfo.id]
8173
if found == false {
8274
producers[p.peerInfo.id] = p
8375
}
76+
8477
return !found
8578
}
8679

8780
// remove a producer from a registration
8881
func (r *RegistrationDB) RemoveProducer(k Registration, id string) (bool, int) {
8982
r.Lock()
9083
defer r.Unlock()
91-
producers, ok := r.registrationMap[k]
84+
value, ok := r.registrationMap.Load(k)
9285
if !ok {
9386
return false, 0
9487
}
88+
producers := value.(ProducerMap)
9589
removed := false
9690
if _, exists := producers[id]; exists {
9791
removed = true
9892
}
9993

10094
// Note: this leaves keys in the DB even if they have empty lists
10195
delete(producers, id)
96+
10297
return removed, len(producers)
10398
}
10499

105100
// remove a Registration and all it's producers
106101
func (r *RegistrationDB) RemoveRegistration(k Registration) {
107-
r.Lock()
108-
defer r.Unlock()
109-
delete(r.registrationMap, k)
102+
r.registrationMap.Delete(k)
110103
}
111104

112105
func (r *RegistrationDB) needFilter(key string, subkey string) bool {
113106
return key == "*" || subkey == "*"
114107
}
115108

116109
func (r *RegistrationDB) FindRegistrations(category string, key string, subkey string) Registrations {
117-
r.RLock()
118-
defer r.RUnlock()
119110
if !r.needFilter(key, subkey) {
120111
k := Registration{category, key, subkey}
121-
if _, ok := r.registrationMap[k]; ok {
112+
if _, ok := r.registrationMap.Load(k); ok {
122113
return Registrations{k}
123114
}
124115
return Registrations{}
125116
}
126117
results := Registrations{}
127-
for k := range r.registrationMap {
128-
if !k.IsMatch(category, key, subkey) {
129-
continue
118+
r.registrationMap.Range(func(k, _ interface{}) bool {
119+
if k.(Registration).IsMatch(category, key, subkey) {
120+
results = append(results, k.(Registration))
130121
}
131-
results = append(results, k)
132-
}
122+
return true
123+
})
124+
133125
return results
134126
}
135127

136128
func (r *RegistrationDB) FindProducers(category string, key string, subkey string) Producers {
137-
r.RLock()
138-
defer r.RUnlock()
139129
if !r.needFilter(key, subkey) {
140130
k := Registration{category, key, subkey}
141-
return ProducerMap2Slice(r.registrationMap[k])
131+
val, _ := r.registrationMap.Load(k)
132+
133+
r.RLock()
134+
defer r.RUnlock()
135+
return ProducerMap2Slice(val.(ProducerMap))
142136
}
143137

138+
r.RLock()
144139
results := make(map[string]struct{})
145140
var retProducers Producers
146-
for k, producers := range r.registrationMap {
147-
if !k.IsMatch(category, key, subkey) {
148-
continue
149-
}
150-
for _, producer := range producers {
151-
_, found := results[producer.peerInfo.id]
152-
if found == false {
153-
results[producer.peerInfo.id] = struct{}{}
154-
retProducers = append(retProducers, producer)
141+
r.registrationMap.Range(func(k, v interface{}) bool {
142+
if k.(Registration).IsMatch(category, key, subkey) {
143+
producers := v.(ProducerMap)
144+
for _, producer := range producers {
145+
_, found := results[producer.peerInfo.id]
146+
if found == false {
147+
results[producer.peerInfo.id] = struct{}{}
148+
retProducers = append(retProducers, producer)
149+
}
155150
}
156151
}
157-
}
152+
return true
153+
})
154+
155+
r.RUnlock()
156+
158157
return retProducers
159158
}
160159

161160
func (r *RegistrationDB) LookupRegistrations(id string) Registrations {
162161
r.RLock()
163-
defer r.RUnlock()
162+
164163
results := Registrations{}
165-
for k, producers := range r.registrationMap {
164+
r.registrationMap.Range(func(k, v interface{}) bool {
165+
producers := v.(ProducerMap)
166166
if _, exists := producers[id]; exists {
167-
results = append(results, k)
167+
results = append(results, k.(Registration))
168168
}
169-
}
169+
170+
return true
171+
})
172+
173+
r.RUnlock()
174+
170175
return results
171176
}
172177

0 commit comments

Comments
 (0)