packer/rpc: edge-triggerd state changes for faster dial/accept
This commit is contained in:
parent
d9f79b0ecc
commit
f79daa0b1b
|
@ -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) {
|
||||||
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()
|
||||||
|
@ -207,6 +209,7 @@ func (m *MuxConn) openStream(id uint32) (*Stream, error) {
|
||||||
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 {
|
||||||
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() {
|
||||||
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:
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue