Skip to content

Commit 4baa574

Browse files
authored
Merge pull request #21434 from karalabe/ethstats-split-rwlock
ethstats: split read and write lock, otherwise they'll lock up
2 parents cbbc54c + 9f45d6e commit 4baa574

File tree

1 file changed

+18
-14
lines changed

1 file changed

+18
-14
lines changed

ethstats/ethstats.go

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -99,19 +99,20 @@ type Service struct {
9999

100100
// connWrapper is a wrapper to prevent concurrent-write or concurrent-read on the
101101
// websocket.
102-
// From Gorilla websocket docs:
103-
// Connections support one concurrent reader and one concurrent writer.
104-
// Applications are responsible for ensuring that no more than one goroutine calls the write methods
105-
// - NextWriter, SetWriteDeadline, WriteMessage, WriteJSON, EnableWriteCompression, SetCompressionLevel
106-
// concurrently and that no more than one goroutine calls the read methods
107-
// - NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler
108-
// concurrently.
109-
// The Close and WriteControl methods can be called concurrently with all other methods.
110102
//
111-
// The connWrapper uses a single mutex for both reading and writing.
103+
// From Gorilla websocket docs:
104+
// Connections support one concurrent reader and one concurrent writer.
105+
// Applications are responsible for ensuring that no more than one goroutine calls the write methods
106+
// - NextWriter, SetWriteDeadline, WriteMessage, WriteJSON, EnableWriteCompression, SetCompressionLevel
107+
// concurrently and that no more than one goroutine calls the read methods
108+
// - NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler
109+
// concurrently.
110+
// The Close and WriteControl methods can be called concurrently with all other methods.
112111
type connWrapper struct {
113112
conn *websocket.Conn
114-
mu sync.Mutex
113+
114+
rlock sync.Mutex
115+
wlock sync.Mutex
115116
}
116117

117118
func newConnectionWrapper(conn *websocket.Conn) *connWrapper {
@@ -120,15 +121,17 @@ func newConnectionWrapper(conn *websocket.Conn) *connWrapper {
120121

121122
// WriteJSON wraps corresponding method on the websocket but is safe for concurrent calling
122123
func (w *connWrapper) WriteJSON(v interface{}) error {
123-
w.mu.Lock()
124-
defer w.mu.Unlock()
124+
w.wlock.Lock()
125+
defer w.wlock.Unlock()
126+
125127
return w.conn.WriteJSON(v)
126128
}
127129

128130
// ReadJSON wraps corresponding method on the websocket but is safe for concurrent calling
129131
func (w *connWrapper) ReadJSON(v interface{}) error {
130-
w.mu.Lock()
131-
defer w.mu.Unlock()
132+
w.rlock.Lock()
133+
defer w.rlock.Unlock()
134+
132135
return w.conn.ReadJSON(v)
133136
}
134137

@@ -275,6 +278,7 @@ func (s *Service) loop() {
275278
continue
276279
}
277280
go s.readLoop(conn)
281+
278282
// Send the initial stats so our node looks decent from the get go
279283
if err = s.report(conn); err != nil {
280284
log.Warn("Initial stats report failed", "err", err)

0 commit comments

Comments
 (0)