|
@@ -47,10 +47,10 @@ type Channel struct {
|
47
|
47
|
userLimit int
|
48
|
48
|
accountToUMode map[string]modes.Mode
|
49
|
49
|
history history.Buffer
|
50
|
|
- stateMutex sync.RWMutex // tier 1
|
51
|
|
- writerSemaphore utils.Semaphore // tier 1.5
|
52
|
|
- joinPartMutex sync.Mutex // tier 3
|
53
|
|
- ensureLoaded utils.Once // manages loading stored registration info from the database
|
|
50
|
+ stateMutex sync.RWMutex // tier 1
|
|
51
|
+ writebackLock sync.Mutex // tier 1.5
|
|
52
|
+ joinPartMutex sync.Mutex // tier 3
|
|
53
|
+ ensureLoaded utils.Once // manages loading stored registration info from the database
|
54
|
54
|
dirtyBits uint
|
55
|
55
|
settings ChannelSettings
|
56
|
56
|
}
|
|
@@ -61,12 +61,11 @@ func NewChannel(s *Server, name, casefoldedName string, registered bool) *Channe
|
61
|
61
|
config := s.Config()
|
62
|
62
|
|
63
|
63
|
channel := &Channel{
|
64
|
|
- createdTime: time.Now().UTC(), // may be overwritten by applyRegInfo
|
65
|
|
- members: make(MemberSet),
|
66
|
|
- name: name,
|
67
|
|
- nameCasefolded: casefoldedName,
|
68
|
|
- server: s,
|
69
|
|
- writerSemaphore: utils.NewSemaphore(1),
|
|
64
|
+ createdTime: time.Now().UTC(), // may be overwritten by applyRegInfo
|
|
65
|
+ members: make(MemberSet),
|
|
66
|
+ name: name,
|
|
67
|
+ nameCasefolded: casefoldedName,
|
|
68
|
+ server: s,
|
70
|
69
|
}
|
71
|
70
|
|
72
|
71
|
channel.initializeLists()
|
|
@@ -209,11 +208,11 @@ func (channel *Channel) MarkDirty(dirtyBits uint) {
|
209
|
208
|
// ChannelManager's lock (that way, no one can join and make the channel dirty again
|
210
|
209
|
// between this method exiting and the actual deletion).
|
211
|
210
|
func (channel *Channel) IsClean() bool {
|
212
|
|
- if !channel.writerSemaphore.TryAcquire() {
|
|
211
|
+ if !channel.writebackLock.TryLock() {
|
213
|
212
|
// a database write (which may fail) is in progress, the channel cannot be cleaned up
|
214
|
213
|
return false
|
215
|
214
|
}
|
216
|
|
- defer channel.writerSemaphore.Release()
|
|
215
|
+ defer channel.writebackLock.Unlock()
|
217
|
216
|
|
218
|
217
|
channel.stateMutex.RLock()
|
219
|
218
|
defer channel.stateMutex.RUnlock()
|
|
@@ -225,7 +224,7 @@ func (channel *Channel) IsClean() bool {
|
225
|
224
|
}
|
226
|
225
|
|
227
|
226
|
func (channel *Channel) wakeWriter() {
|
228
|
|
- if channel.writerSemaphore.TryAcquire() {
|
|
227
|
+ if channel.writebackLock.TryLock() {
|
229
|
228
|
go channel.writeLoop()
|
230
|
229
|
}
|
231
|
230
|
}
|
|
@@ -235,7 +234,7 @@ func (channel *Channel) writeLoop() {
|
235
|
234
|
for {
|
236
|
235
|
// TODO(#357) check the error value of this and implement timed backoff
|
237
|
236
|
channel.performWrite(0)
|
238
|
|
- channel.writerSemaphore.Release()
|
|
237
|
+ channel.writebackLock.Unlock()
|
239
|
238
|
|
240
|
239
|
channel.stateMutex.RLock()
|
241
|
240
|
isDirty := channel.dirtyBits != 0
|
|
@@ -249,7 +248,7 @@ func (channel *Channel) writeLoop() {
|
249
|
248
|
return // nothing to do
|
250
|
249
|
} // else: isDirty, so we need to write again
|
251
|
250
|
|
252
|
|
- if !channel.writerSemaphore.TryAcquire() {
|
|
251
|
+ if !channel.writebackLock.TryLock() {
|
253
|
252
|
return
|
254
|
253
|
}
|
255
|
254
|
}
|
|
@@ -272,8 +271,8 @@ func (channel *Channel) Store(dirtyBits uint) (err error) {
|
272
|
271
|
}
|
273
|
272
|
}()
|
274
|
273
|
|
275
|
|
- channel.writerSemaphore.Acquire()
|
276
|
|
- defer channel.writerSemaphore.Release()
|
|
274
|
+ channel.writebackLock.Lock()
|
|
275
|
+ defer channel.writebackLock.Unlock()
|
277
|
276
|
return channel.performWrite(dirtyBits)
|
278
|
277
|
}
|
279
|
278
|
|