Commit f79daa0b authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

packer/rpc: edge-triggerd state changes for faster dial/accept

parent d9f79b0e
...@@ -84,23 +84,25 @@ func (m *MuxConn) Accept(id uint32) (io.ReadWriteCloser, error) { ...@@ -84,23 +84,25 @@ func (m *MuxConn) Accept(id uint32) (io.ReadWriteCloser, error) {
if stream.state != streamStateEstablished { if stream.state != streamStateEstablished {
// Go into the listening state // Go into the listening state
stream.setState(streamStateListen) stream.setState(streamStateListen)
// Register a state change listener to wait for changes
stateCh := make(chan streamState, 10)
stream.registerStateListener(stateCh)
defer func() {
stream.mu.Lock()
defer stream.mu.Unlock()
stream.deregisterStateListener(stateCh)
}()
stream.mu.Unlock() stream.mu.Unlock()
// Wait for the connection to establish // Wait for the connection to establish
ACCEPT_ESTABLISH_LOOP: ACCEPT_ESTABLISH_LOOP:
for { for {
time.Sleep(50 * time.Millisecond) state := <-stateCh
stream.mu.Lock() switch state {
switch stream.state {
case streamStateListen: case streamStateListen:
stream.mu.Unlock()
case streamStateClosed:
// This can happen if it becomes established, some data is sent,
// and it closed all within the time period we wait above.
// This case will be fixed when we have edge-triggered checks.
fallthrough
case streamStateEstablished: case streamStateEstablished:
stream.mu.Unlock()
break ACCEPT_ESTABLISH_LOOP break ACCEPT_ESTABLISH_LOOP
default: default:
defer stream.mu.Unlock() defer stream.mu.Unlock()
...@@ -137,23 +139,23 @@ func (m *MuxConn) Dial(id uint32) (io.ReadWriteCloser, error) { ...@@ -137,23 +139,23 @@ func (m *MuxConn) Dial(id uint32) (io.ReadWriteCloser, error) {
return nil, err return nil, err
} }
stream.setState(streamStateSynSent) stream.setState(streamStateSynSent)
// Register a state change listener to wait for changes
stateCh := make(chan streamState, 10)
stream.registerStateListener(stateCh)
defer func() {
stream.mu.Lock()
defer stream.mu.Unlock()
stream.deregisterStateListener(stateCh)
}()
stream.mu.Unlock() stream.mu.Unlock()
for { for {
time.Sleep(50 * time.Millisecond) state := <-stateCh
stream.mu.Lock() switch state {
switch stream.state {
case streamStateSynSent: case streamStateSynSent:
stream.mu.Unlock()
case streamStateClosed:
// This can happen if it becomes established, some data is sent,
// and it closed all within the time period we wait above.
// This case will be fixed when we have edge-triggered checks.
fallthrough
case streamStateCloseWait:
fallthrough
case streamStateEstablished: case streamStateEstablished:
stream.mu.Unlock()
return stream, nil return stream, nil
default: default:
defer stream.mu.Unlock() defer stream.mu.Unlock()
...@@ -203,10 +205,11 @@ func (m *MuxConn) openStream(id uint32) (*Stream, error) { ...@@ -203,10 +205,11 @@ func (m *MuxConn) openStream(id uint32) (*Stream, error) {
// Set the data channel so we can write to it. // Set the data channel so we can write to it.
stream := &Stream{ stream := &Stream{
id: id, id: id,
mux: m, mux: m,
reader: dataR, reader: dataR,
writeCh: writeCh, writeCh: writeCh,
stateChange: make(map[chan<- streamState]struct{}),
} }
stream.setState(streamStateClosed) stream.setState(streamStateClosed)
...@@ -364,6 +367,7 @@ type Stream struct { ...@@ -364,6 +367,7 @@ type Stream struct {
mux *MuxConn mux *MuxConn
reader io.Reader reader io.Reader
state streamState state streamState
stateChange map[chan<- streamState]struct{}
stateUpdated time.Time stateUpdated time.Time
mu sync.Mutex mu sync.Mutex
writeCh chan<- []byte writeCh chan<- []byte
...@@ -421,7 +425,21 @@ func (s *Stream) remoteClose() { ...@@ -421,7 +425,21 @@ func (s *Stream) remoteClose() {
s.writeCh <- nil s.writeCh <- nil
} }
func (s *Stream) registerStateListener(ch chan<- streamState) {
s.stateChange[ch] = struct{}{}
}
func (s *Stream) deregisterStateListener(ch chan<- streamState) {
delete(s.stateChange, ch)
}
func (s *Stream) setState(state streamState) { func (s *Stream) setState(state streamState) {
s.state = state s.state = state
s.stateUpdated = time.Now().UTC() s.stateUpdated = time.Now().UTC()
for ch, _ := range s.stateChange {
select {
case ch <- state:
default:
}
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment