func (r *ReadBuffer) Wrap(b []byte) {
	r.buffer = b
	r.remaining = b
	r.err = nil
}

func ( r * ReadBuffer ) Wrap ( b [ ] byte ) { r . buffer = b r . remaining = b r . err = nil }

// Wrap initializes the buffer to read from the given byte slice


func (w *WriteBuffer) WriteSingleByte(n byte) {
	if w.err != nil {
		return
	}

	if len(w.remaining) == 0 {
		w.setErr(ErrBufferFull)
		return
	}

	w.remaining[0] = n
	w.remaining = w.remaining[1:]
}

func ( w * WriteBuffer ) WriteSingleByte ( n byte ) { if w . err != nil { return } if len ( w . remaining ) == 0 { w . setErr ( ErrBufferFull ) return } w . remaining [ 0 ] = n w . remaining = w . remaining [ 1 : ] }

// WriteSingleByte writes a single byte to the buffer


func (w *WriteBuffer) WriteBytes(in []byte) {
	if b := w.reserve(len(in)); b != nil {
		copy(b, in)
	}
}

func ( w * WriteBuffer ) WriteBytes ( in [ ] byte ) { if b := w . reserve ( len ( in ) ) ; b != nil { copy ( b , in ) } }

// WriteBytes writes a slice of bytes to the buffer


func (w *WriteBuffer) WriteUint16(n uint16) {
	if b := w.reserve(2); b != nil {
		binary.BigEndian.PutUint16(b, n)
	}
}

func ( w * WriteBuffer ) WriteUint16 ( n uint16 ) { if b := w . reserve ( 2 ) ; b != nil { binary . BigEndian . PutUint16 ( b , n ) } }

// WriteUint16 writes a big endian encoded uint16 value to the buffer


func (w *WriteBuffer) WriteUint32(n uint32) {
	if b := w.reserve(4); b != nil {
		binary.BigEndian.PutUint32(b, n)
	}
}

func ( w * WriteBuffer ) WriteUint32 ( n uint32 ) { if b := w . reserve ( 4 ) ; b != nil { binary . BigEndian . PutUint32 ( b , n ) } }

// WriteUint32 writes a big endian uint32 value to the buffer


func (w *WriteBuffer) WriteUint64(n uint64) {
	if b := w.reserve(8); b != nil {
		binary.BigEndian.PutUint64(b, n)
	}
}

func ( w * WriteBuffer ) WriteUint64 ( n uint64 ) { if b := w . reserve ( 8 ) ; b != nil { binary . BigEndian . PutUint64 ( b , n ) } }

// WriteUint64 writes a big endian uint64 to the buffer


func (w *WriteBuffer) WriteUvarint(n uint64) {
	// A uvarint could be up to 10 bytes long.
	buf := make([]byte, 10)
	varBytes := binary.PutUvarint(buf, n)
	if b := w.reserve(varBytes); b != nil {
		copy(b, buf[0:varBytes])
	}
}

// WriteUvarint writes an unsigned varint to the buffer


func (w *WriteBuffer) WriteString(s string) {
	// NB(mmihic): Don't just call WriteBytes; that will make a double copy
	// of the string due to the cast
	if b := w.reserve(len(s)); b != nil {
		copy(b, s)
	}
}

// WriteString writes a string to the buffer


func (w *WriteBuffer) WriteLen8String(s string) {
	if int(byte(len(s))) != len(s) {
		w.setErr(errStringTooLong)
	}

	w.WriteSingleByte(byte(len(s)))
	w.WriteString(s)
}

func ( w * WriteBuffer ) WriteLen8String ( s string ) { if int ( byte ( len ( s ) ) ) != len ( s ) { w . setErr ( errStringTooLong ) } w . WriteSingleByte ( byte ( len ( s ) ) ) w . WriteString ( s ) }

// WriteLen8String writes an 8-bit length preceded string

WriteLen8String writes an 8 - bit length preceded string


func (w *WriteBuffer) WriteLen16String(s string) {
	if int(uint16(len(s))) != len(s) {
		w.setErr(errStringTooLong)
	}

	w.WriteUint16(uint16(len(s)))
	w.WriteString(s)
}

func ( w * WriteBuffer ) WriteLen16String ( s string ) { if int ( uint16 ( len ( s ) ) ) != len ( s ) { w . setErr ( errStringTooLong ) } w . WriteUint16 ( uint16 ( len ( s ) ) ) w . WriteString ( s ) }

// WriteLen16String writes a 16-bit length preceded string

WriteLen16String writes a 16 - bit length preceded string


func (w *WriteBuffer) DeferByte() ByteRef {
	if len(w.remaining) == 0 {
		w.setErr(ErrBufferFull)
		return ByteRef(nil)
	}

	// Always zero out references, since the caller expects the default to be 0.
	w.remaining[0] = 0
	bufRef := ByteRef(w.remaining[0:])
	w.remaining = w.remaining[1:]
	return bufRef
}

// DeferByte reserves space in the buffer for a single byte, and returns a
// reference that can be used to update that byte later

DeferByte reserves space in the buffer for a single byte and returns a reference that can be used to update that byte later


func (w *WriteBuffer) DeferBytes(n int) BytesRef {
	return BytesRef(w.deferred(n))
}

func ( w * WriteBuffer ) DeferBytes ( n int ) BytesRef { return BytesRef ( w . deferred ( n ) ) }

// DeferBytes reserves space in the buffer for a fixed sequence of bytes, and
// returns a reference that can be used to update those bytes

DeferBytes reserves space in the buffer for a fixed sequence of bytes and returns a reference that can be used to update those bytes


func (w *WriteBuffer) FlushTo(iow io.Writer) (int, error) {
	dirty := w.buffer[0:w.BytesWritten()]
	return iow.Write(dirty)
}

func ( w * WriteBuffer ) FlushTo ( iow io . Writer ) ( int , error ) { dirty := w . buffer [ 0 : w . BytesWritten ( ) ] return iow . Write ( dirty ) }

// FlushTo flushes the written buffer to the given writer


func (w *WriteBuffer) Reset() {
	w.remaining = w.buffer
	w.err = nil
}

func ( w * WriteBuffer ) Reset ( ) { w . remaining = w . buffer w . err = nil }

// Reset resets the buffer to an empty state, ready for writing

Reset resets the buffer to an empty state ready for writing


func (w *WriteBuffer) Wrap(b []byte) {
	w.buffer = b
	w.remaining = b
}

func ( w * WriteBuffer ) Wrap ( b [ ] byte ) { w . buffer = b w . remaining = b }

// Wrap initializes the buffer to wrap the given byte slice


func (ref Uint16Ref) Update(n uint16) {
	if ref != nil {
		binary.BigEndian.PutUint16(ref, n)
	}
}

func ( ref Uint16Ref ) Update ( n uint16 ) { if ref != nil { binary . BigEndian . PutUint16 ( ref , n ) } }

// Update updates the uint16 in the buffer


func (ref Uint32Ref) Update(n uint32) {
	if ref != nil {
		binary.BigEndian.PutUint32(ref, n)
	}
}

func ( ref Uint32Ref ) Update ( n uint32 ) { if ref != nil { binary . BigEndian . PutUint32 ( ref , n ) } }

// Update updates the uint32 in the buffer


func (ref Uint64Ref) Update(n uint64) {
	if ref != nil {
		binary.BigEndian.PutUint64(ref, n)
	}
}

func ( ref Uint64Ref ) Update ( n uint64 ) { if ref != nil { binary . BigEndian . PutUint64 ( ref , n ) } }

// Update updates the uint64 in the buffer


func (ref BytesRef) Update(b []byte) {
	if ref != nil {
		copy(ref, b)
	}
}

func ( ref BytesRef ) Update ( b [ ] byte ) { if ref != nil { copy ( ref , b ) } }

// Update updates the bytes in the buffer


func (ref BytesRef) UpdateString(s string) {
	if ref != nil {
		copy(ref, s)
	}
}

func ( ref BytesRef ) UpdateString ( s string ) { if ref != nil { copy ( ref , s ) } }

// UpdateString updates the bytes in the buffer from a string


func (r *fragmentingReader) ArgReader(last bool) (ArgReader, error) {
	if err := r.BeginArgument(last); err != nil {
		return nil, err
	}
	return r, nil
}

func ( r * fragmentingReader ) ArgReader ( last bool ) ( ArgReader , error ) { if err := r . BeginArgument ( last ) ; err != nil { return nil , err } return r , nil }

// The ArgReader will handle fragmentation as needed. Once the argument has
// been read, the ArgReader must be closed.

The ArgReader will handle fragmentation as needed . Once the argument has been read the ArgReader must be closed .


func (f *writableFragment) finish(hasMoreFragments bool) {
	f.checksumRef.Update(f.checksum.Sum())
	if hasMoreFragments {
		f.flagsRef.Update(hasMoreFragmentsFlag)
	} else {
		f.checksum.Release()
	}
}

func ( f * writableFragment ) finish ( hasMoreFragments bool ) { f . checksumRef . Update ( f . checksum . Sum ( ) ) if hasMoreFragments { f . flagsRef . Update ( hasMoreFragmentsFlag ) } else { f . checksum . Release ( ) } }

// finish finishes the fragment, updating the final checksum and fragment flags

finish finishes the fragment updating the final checksum and fragment flags


func newWritableChunk(checksum Checksum, contents *typed.WriteBuffer) *writableChunk {
	return &writableChunk{
		size:     0,
		sizeRef:  contents.DeferUint16(),
		checksum: checksum,
		contents: contents,
	}
}

func newWritableChunk ( checksum Checksum , contents * typed . WriteBuffer ) * writableChunk { return & writableChunk { size : 0 , sizeRef : contents . DeferUint16 ( ) , checksum : checksum , contents : contents , } }

// newWritableChunk creates a new writable chunk around a checksum and a buffer to hold data


func (c *writableChunk) writeAsFits(b []byte) int {
	if len(b) > c.contents.BytesRemaining() {
		b = b[:c.contents.BytesRemaining()]
	}

	c.checksum.Add(b)
	c.contents.WriteBytes(b)

	written := len(b)
	c.size += uint16(written)
	return written
}

func ( c * writableChunk ) writeAsFits ( b [ ] byte ) int { if len ( b ) > c . contents . BytesRemaining ( ) { b = b [ : c . contents . BytesRemaining ( ) ] } c . checksum . Add ( b ) c . contents . WriteBytes ( b ) written := len ( b ) c . size += uint16 ( written ) return written }

// writeAsFits writes as many bytes from the given slice as fits into the chunk


func newFragmentingWriter(logger Logger, sender fragmentSender, checksum Checksum) *fragmentingWriter {
	return &fragmentingWriter{
		logger:   logger,
		sender:   sender,
		checksum: checksum,
		state:    fragmentingWriteStart,
	}
}

func newFragmentingWriter ( logger Logger , sender fragmentSender , checksum Checksum ) * fragmentingWriter { return & fragmentingWriter { logger : logger , sender : sender , checksum : checksum , state : fragmentingWriteStart , } }

// newFragmentingWriter creates a new fragmenting writer


func (w *fragmentingWriter) ArgWriter(last bool) (ArgWriter, error) {
	if err := w.BeginArgument(last); err != nil {
		return nil, err
	}
	return w, nil
}

func ( w * fragmentingWriter ) ArgWriter ( last bool ) ( ArgWriter , error ) { if err := w . BeginArgument ( last ) ; err != nil { return nil , err } return w , nil }

// ArgWriter returns an ArgWriter to write an argument. The ArgWriter will handle
// fragmentation as needed. Once the argument is written, the ArgWriter must be closed.

ArgWriter returns an ArgWriter to write an argument . The ArgWriter will handle fragmentation as needed . Once the argument is written the ArgWriter must be closed .


func (w *fragmentingWriter) BeginArgument(last bool) error {
	if w.err != nil {
		return w.err
	}

	switch {
	case w.state == fragmentingWriteComplete:
		w.err = errComplete
		return w.err
	case w.state.isWritingArgument():
		w.err = errAlreadyWritingArgument
		return w.err
	}

	// If we don't have a fragment, request one
	if w.curFragment == nil {
		initial := w.state == fragmentingWriteStart
		if w.curFragment, w.err = w.sender.newFragment(initial, w.checksum); w.err != nil {
			return w.err
		}
	}

	// If there's no room in the current fragment, freak out.  This will
	// only happen due to an implementation error in the TChannel stack
	// itself
	if w.curFragment.contents.BytesRemaining() <= chunkHeaderSize {
		panic(fmt.Errorf("attempting to begin an argument in a fragment with only %d bytes available",
			w.curFragment.contents.BytesRemaining()))
	}

	w.curChunk = newWritableChunk(w.checksum, w.curFragment.contents)
	w.state = fragmentingWriteInArgument
	if last {
		w.state = fragmentingWriteInLastArgument
	}
	return nil
}

// BeginArgument tells the writer that the caller is starting a new argument.
// Must not be called while an existing argument is in place

BeginArgument tells the writer that the caller is starting a new argument . Must not be called while an existing argument is in place


func (w *fragmentingWriter) Write(b []byte) (int, error) {
	if w.err != nil {
		return 0, w.err
	}

	if !w.state.isWritingArgument() {
		w.err = errNotWritingArgument
		return 0, w.err
	}

	totalWritten := 0
	for {
		bytesWritten := w.curChunk.writeAsFits(b)
		totalWritten += bytesWritten
		if bytesWritten == len(b) {
			// The whole thing fit, we're done
			return totalWritten, nil
		}

		// There was more data than fit into the fragment, so flush the current fragment,
		// start a new fragment and chunk, and continue writing
		if w.err = w.Flush(); w.err != nil {
			return totalWritten, w.err
		}

		b = b[bytesWritten:]
	}
}

// Write writes argument data, breaking it into fragments as needed

Write writes argument data breaking it into fragments as needed


func (w *fragmentingWriter) Flush() error {
	w.curChunk.finish()
	w.curFragment.finish(true)
	if w.err = w.sender.flushFragment(w.curFragment); w.err != nil {
		return w.err
	}

	if w.curFragment, w.err = w.sender.newFragment(false, w.checksum); w.err != nil {
		return w.err
	}

	w.curChunk = newWritableChunk(w.checksum, w.curFragment.contents)
	return nil
}

func ( w * fragmentingWriter ) Flush ( ) error { w . curChunk . finish ( ) w . curFragment . finish ( true ) if w . err = w . sender . flushFragment ( w . curFragment ) ; w . err != nil { return w . err } if w . curFragment , w . err = w . sender . newFragment ( false , w . checksum ) ; w . err != nil { return w . err } w . curChunk = newWritableChunk ( w . checksum , w . curFragment . contents ) return nil }

// Flush flushes the current fragment, and starts a new fragment and chunk.

Flush flushes the current fragment and starts a new fragment and chunk .


func (w *fragmentingWriter) Close() error {
	last := w.state == fragmentingWriteInLastArgument
	if w.err != nil {
		return w.err
	}

	if !w.state.isWritingArgument() {
		w.err = errNotWritingArgument
		return w.err
	}

	w.curChunk.finish()

	// There are three possibilities here:
	// 1. There are no more arguments
	//      flush with more_fragments=false, mark the stream as complete
	// 2. There are more arguments, but we can't fit more data into this fragment
	//      flush with more_fragments=true, start new fragment, write empty chunk to indicate
	//      the current argument is complete
	// 3. There are more arguments, and we can fit more data into this fragment
	//      update the chunk but leave the current fragment open
	if last {
		// No more arguments - flush this final fragment and mark ourselves complete
		w.state = fragmentingWriteComplete
		w.curFragment.finish(false)
		w.err = w.sender.flushFragment(w.curFragment)
		w.sender.doneSending()
		return w.err
	}

	w.state = fragmentingWriteWaitingForArgument
	if w.curFragment.contents.BytesRemaining() > chunkHeaderSize {
		// There's enough room in this fragment for the next argument's
		// initial chunk, so we're done here
		return nil
	}

	// This fragment is full - flush and prepare for another argument
	w.curFragment.finish(true)
	if w.err = w.sender.flushFragment(w.curFragment); w.err != nil {
		return w.err
	}

	if w.curFragment, w.err = w.sender.newFragment(false, w.checksum); w.err != nil {
		return w.err
	}

	// Write an empty chunk to indicate this argument has ended
	w.curFragment.contents.WriteUint16(0)
	return nil
}

//      the current argument is complete


func (c *Connection) handleCallRes(frame *Frame) bool {
	if err := c.outbound.forwardPeerFrame(frame); err != nil {
		return true
	}
	return false
}

func ( c * Connection ) handleCallRes ( frame * Frame ) bool { if err := c . outbound . forwardPeerFrame ( frame ) ; err != nil { return true } return false }

// handleCallRes handles an incoming call req message, forwarding the
// frame to the response channel waiting for it

handleCallRes handles an incoming call req message forwarding the frame to the response channel waiting for it


func (response *OutboundCallResponse) Arg2Reader() (ArgReader, error) {
	var method []byte
	if err := NewArgReader(response.arg1Reader()).Read(&method); err != nil {
		return nil, err
	}

	return response.arg2Reader()
}

func ( response * OutboundCallResponse ) Arg2Reader ( ) ( ArgReader , error ) { var method [ ] byte if err := NewArgReader ( response . arg1Reader ( ) ) . Read ( & method ) ; err != nil { return nil , err } return response . arg2Reader ( ) }

// Arg2Reader returns an ArgReader to read the second argument.
// The ReadCloser must be closed once the argument has been read.

Arg2Reader returns an ArgReader to read the second argument . The ReadCloser must be closed once the argument has been read .


func (c *Connection) handleError(frame *Frame) bool {
	errMsg := errorMessage{
		id: frame.Header.ID,
	}
	rbuf := typed.NewReadBuffer(frame.SizedPayload())
	if err := errMsg.read(rbuf); err != nil {
		c.log.WithFields(
			LogField{"remotePeer", c.remotePeerInfo},
			ErrField(err),
		).Warn("Unable to read error frame.")
		c.connectionError("parsing error frame", err)
		return true
	}

	if errMsg.errCode == ErrCodeProtocol {
		c.log.WithFields(
			LogField{"remotePeer", c.remotePeerInfo},
			LogField{"error", errMsg.message},
		).Warn("Peer reported protocol error.")
		c.connectionError("received protocol error", errMsg.AsSystemError())
		return true
	}

	if err := c.outbound.forwardPeerFrame(frame); err != nil {
		c.log.WithFields(
			LogField{"frameHeader", frame.Header.String()},
			LogField{"id", errMsg.id},
			LogField{"errorMessage", errMsg.message},
			LogField{"errorCode", errMsg.errCode},
			ErrField(err),
		).Info("Failed to forward error frame.")
		return true
	}

	// If the frame was forwarded, then the other side is responsible for releasing the frame.
	return false
}

// handleError handles an error coming back from the peer. If the error is a
// protocol level error, the entire connection will be closed.  If the error is
// a request specific error, it will be written to the request's response
// channel and converted into a SystemError returned from the next reader or
// access call.
// The return value is whether the frame should be released immediately.

handleError handles an error coming back from the peer . If the error is a protocol level error the entire connection will be closed . If the error is a request specific error it will be written to the request s response channel and converted into a SystemError returned from the next reader or access call . The return value is whether the frame should be released immediately .


func (response *OutboundCallResponse) doneReading(unexpected error) {
	now := response.timeNow()

	isSuccess := unexpected == nil && !response.ApplicationError()
	lastAttempt := isSuccess || !response.requestState.HasRetries(unexpected)

	// TODO how should this work with retries?
	if span := response.span; span != nil {
		if unexpected != nil {
			span.LogEventWithPayload("error", unexpected)
		}
		if !isSuccess && lastAttempt {
			ext.Error.Set(span, true)
		}
		span.FinishWithOptions(opentracing.FinishOptions{FinishTime: now})
	}

	latency := now.Sub(response.startedAt)
	response.statsReporter.RecordTimer("outbound.calls.per-attempt.latency", response.commonStatsTags, latency)
	if lastAttempt {
		requestLatency := response.requestState.SinceStart(now, latency)
		response.statsReporter.RecordTimer("outbound.calls.latency", response.commonStatsTags, requestLatency)
	}
	if retryCount := response.requestState.RetryCount(); retryCount > 0 {
		retryTags := cloneTags(response.commonStatsTags)
		retryTags["retry-count"] = fmt.Sprint(retryCount)
		response.statsReporter.IncCounter("outbound.calls.retries", retryTags, 1)
	}

	if unexpected != nil {
		// TODO(prashant): Report the error code type as per metrics doc and enable.
		// response.statsReporter.IncCounter("outbound.calls.system-errors", response.commonStatsTags, 1)
	} else if response.ApplicationError() {
		// TODO(prashant): Figure out how to add "type" to tags, which TChannel does not know about.
		response.statsReporter.IncCounter("outbound.calls.per-attempt.app-errors", response.commonStatsTags, 1)
		if lastAttempt {
			response.statsReporter.IncCounter("outbound.calls.app-errors", response.commonStatsTags, 1)
		}
	} else {
		response.statsReporter.IncCounter("outbound.calls.success", response.commonStatsTags, 1)
	}

	response.mex.shutdown()
}

// doneReading shuts down the message exchange for this call.
// For outgoing calls, the last message is reading the call response.

doneReading shuts down the message exchange for this call . For outgoing calls the last message is reading the call response .


func (w *reqResWriter) newFragment(initial bool, checksum Checksum) (*writableFragment, error) {
	if err := w.mex.checkError(); err != nil {
		return nil, w.failed(err)
	}

	message := w.messageForFragment(initial)

	// Create the frame
	frame := w.conn.opts.FramePool.Get()
	frame.Header.ID = w.mex.msgID
	frame.Header.messageType = message.messageType()

	// Write the message into the fragment, reserving flags and checksum bytes
	wbuf := typed.NewWriteBuffer(frame.Payload[:])
	fragment := new(writableFragment)
	fragment.frame = frame
	fragment.flagsRef = wbuf.DeferByte()
	if err := message.write(wbuf); err != nil {
		return nil, err
	}
	wbuf.WriteSingleByte(byte(checksum.TypeCode()))
	fragment.checksumRef = wbuf.DeferBytes(checksum.Size())
	fragment.checksum = checksum
	fragment.contents = wbuf
	return fragment, wbuf.Err()
}

// newFragment creates a new fragment for marshaling into


func (w *reqResWriter) flushFragment(fragment *writableFragment) error {
	if w.err != nil {
		return w.err
	}

	frame := fragment.frame.(*Frame)
	frame.Header.SetPayloadSize(uint16(fragment.contents.BytesWritten()))

	if err := w.mex.checkError(); err != nil {
		return w.failed(err)
	}
	select {
	case <-w.mex.ctx.Done():
		return w.failed(GetContextError(w.mex.ctx.Err()))
	case <-w.mex.errCh.c:
		return w.failed(w.mex.errCh.err)
	case w.conn.sendCh <- frame:
		return nil
	}
}

func ( w * reqResWriter ) flushFragment ( fragment * writableFragment ) error { if w . err != nil { return w . err } frame := fragment . frame . ( * Frame ) frame . Header . SetPayloadSize ( uint16 ( fragment . contents . BytesWritten ( ) ) ) if err := w . mex . checkError ( ) ; err != nil { return w . failed ( err ) } select { case <- w . mex . ctx . Done ( ) : return w . failed ( GetContextError ( w . mex . ctx . Err ( ) ) ) case <- w . mex . errCh . c : return w . failed ( w . mex . errCh . err ) case w . conn . sendCh <- frame : return nil } }

// flushFragment sends a fragment to the peer over the connection


func (w *reqResWriter) failed(err error) error {
	w.log.Debugf("writer failed: %v existing err: %v", err, w.err)
	if w.err != nil {
		return w.err
	}

	w.mex.shutdown()
	w.err = err
	return w.err
}

func ( w * reqResWriter ) failed ( err error ) error { w . log . Debugf ( " " , err , w . err ) if w . err != nil { return w . err } w . mex . shutdown ( ) w . err = err return w . err }

// failed marks the writer as having failed


func (r *reqResReader) arg1Reader() (ArgReader, error) {
	return r.argReader(false /* last */, reqResReaderPreArg1, reqResReaderPreArg2)
}

func
(
r
*
reqResReader
)
arg1Reader
(
)
(
ArgReader
,
error
)
{
return
r
.
argReader
(
false
/* last */
,
reqResReaderPreArg1
,
reqResReaderPreArg2
)
}

// arg1Reader returns an ArgReader to read arg1.

arg1Reader returns an ArgReader to read arg1 .


func (r *reqResReader) arg2Reader() (ArgReader, error) {
	return r.argReader(false /* last */, reqResReaderPreArg2, reqResReaderPreArg3)
}

func
(
r
*
reqResReader
)
arg2Reader
(
)
(
ArgReader
,
error
)
{
return
r
.
argReader
(
false
/* last */
,
reqResReaderPreArg2
,
reqResReaderPreArg3
)
}

// arg2Reader returns an ArgReader to read arg2.

arg2Reader returns an ArgReader to read arg2 .


func (r *reqResReader) arg3Reader() (ArgReader, error) {
	return r.argReader(true /* last */, reqResReaderPreArg3, reqResReaderComplete)
}

func
(
r
*
reqResReader
)
arg3Reader
(
)
(
ArgReader
,
error
)
{
return
r
.
argReader
(
true
/* last */
,
reqResReaderPreArg3
,
reqResReaderComplete
)
}

// arg3Reader returns an ArgReader to read arg3.

arg3Reader returns an ArgReader to read arg3 .


func (r *reqResReader) argReader(last bool, inState reqResReaderState, outState reqResReaderState) (ArgReader, error) {
	if r.state != inState {
		return nil, r.failed(errReqResReaderStateMismatch{state: r.state, expectedState: inState})
	}

	argReader, err := r.contents.ArgReader(last)
	if err != nil {
		return nil, r.failed(err)
	}

	r.state = outState
	return argReader, nil
}

func ( r * reqResReader ) argReader ( last bool , inState reqResReaderState , outState reqResReaderState ) ( ArgReader , error ) { if r . state != inState { return nil , r . failed ( errReqResReaderStateMismatch { state : r . state , expectedState : inState } ) } argReader , err := r . contents . ArgReader ( last ) if err != nil { return nil , r . failed ( err ) } r . state = outState return argReader , nil }

// argReader returns an ArgReader that can be used to read an argument. The
// ReadCloser must be closed once the argument has been read.

argReader returns an ArgReader that can be used to read an argument . The ReadCloser must be closed once the argument has been read .


func (r *reqResReader) recvNextFragment(initial bool) (*readableFragment, error) {
	if r.initialFragment != nil {
		fragment := r.initialFragment
		r.initialFragment = nil
		r.previousFragment = fragment
		return fragment, nil
	}

	// Wait for the appropriate message from the peer
	message := r.messageForFragment(initial)
	frame, err := r.mex.recvPeerFrameOfType(message.messageType())
	if err != nil {
		if err, ok := err.(errorMessage); ok {
			// If we received a serialized error from the other side, then we should go through
			// the normal doneReading path so stats get updated with this error.
			r.err = err.AsSystemError()
			return nil, err
		}

		return nil, r.failed(err)
	}

	// Parse the message and setup the fragment
	fragment, err := parseInboundFragment(r.mex.framePool, frame, message)
	if err != nil {
		return nil, r.failed(err)
	}

	r.previousFragment = fragment
	return fragment, nil
}

// recvNextFragment receives the next fragment from the underlying message exchange.

recvNextFragment receives the next fragment from the underlying message exchange .


func (r *reqResReader) releasePreviousFragment() {
	fragment := r.previousFragment
	r.previousFragment = nil
	if fragment != nil {
		fragment.done()
	}
}

func ( r * reqResReader ) releasePreviousFragment ( ) { fragment := r . previousFragment r . previousFragment = nil if fragment != nil { fragment . done ( ) } }

// releasePreviousFrament releases the last fragment returned by the reader if
// it's still around. This operation is idempotent.

releasePreviousFrament releases the last fragment returned by the reader if it s still around . This operation is idempotent .


func (r *reqResReader) failed(err error) error {
	r.log.Debugf("reader failed: %v existing err: %v", err, r.err)
	if r.err != nil {
		return r.err
	}

	r.mex.shutdown()
	r.err = err
	return r.err
}

func ( r * reqResReader ) failed ( err error ) error { r . log . Debugf ( " " , err , r . err ) if r . err != nil { return r . err } r . mex . shutdown ( ) r . err = err return r . err }


func parseInboundFragment(framePool FramePool, frame *Frame, message message) (*readableFragment, error) {
	rbuf := typed.NewReadBuffer(frame.SizedPayload())
	fragment := new(readableFragment)
	fragment.flags = rbuf.ReadSingleByte()
	if err := message.read(rbuf); err != nil {
		return nil, err
	}

	fragment.checksumType = ChecksumType(rbuf.ReadSingleByte())
	fragment.checksum = rbuf.ReadBytes(fragment.checksumType.ChecksumSize())
	fragment.contents = rbuf
	fragment.onDone = func() {
		framePool.Release(frame)
	}
	return fragment, rbuf.Err()
}

func parseInboundFragment ( framePool FramePool , frame * Frame , message message ) ( * readableFragment , error ) { rbuf := typed . NewReadBuffer ( frame . SizedPayload ( ) ) fragment := new ( readableFragment ) fragment . flags = rbuf . ReadSingleByte ( ) if err := message . read ( rbuf ) ; err != nil { return nil , err } fragment . checksumType = ChecksumType ( rbuf . ReadSingleByte ( ) ) fragment . checksum = rbuf . ReadBytes ( fragment . checksumType . ChecksumSize ( ) ) fragment . contents = rbuf fragment . onDone = func ( ) { framePool . Release ( frame ) } return fragment , rbuf . Err ( ) }

// parseInboundFragment parses an incoming fragment based on the given message


func NewContext(timeout time.Duration) (Context, context.CancelFunc) {
	ctx, cancel := tchannel.NewContext(timeout)
	return Wrap(ctx), cancel
}

func NewContext ( timeout time . Duration ) ( Context , context . CancelFunc ) { ctx , cancel := tchannel . NewContext ( timeout ) return Wrap ( ctx ) , cancel }

// NewContext returns a Context that can be used to make Thrift calls.

NewContext returns a Context that can be used to make Thrift calls .


func WithHeaders(ctx context.Context, headers map[string]string) Context {
	return tchannel.WrapWithHeaders(ctx, headers)
}

func WithHeaders ( ctx context . Context , headers map [ string ] string ) Context { return tchannel . WrapWithHeaders ( ctx , headers ) }

// WithHeaders returns a Context that can be used to make a call with request headers.

WithHeaders returns a Context that can be used to make a call with request headers .


func (c *Connection) healthCheck(connID uint32) {
	defer close(c.healthCheckDone)

	opts := c.opts.HealthChecks

	ticker := c.timeTicker(opts.Interval)
	defer ticker.Stop()

	consecutiveFailures := 0
	for {
		select {
		case <-ticker.C:
		case <-c.healthCheckCtx.Done():
			return
		}

		ctx, cancel := context.WithTimeout(c.healthCheckCtx, opts.Timeout)
		err := c.ping(ctx)
		cancel()
		c.healthCheckHistory.add(err == nil)
		if err == nil {
			if c.log.Enabled(LogLevelDebug) {
				c.log.Debug("Performed successful active health check.")
			}
			consecutiveFailures = 0
			continue
		}

		// If the health check failed because the connection closed or health
		// checks were stopped, we don't need to log or close the connection.
		if GetSystemErrorCode(err) == ErrCodeCancelled || err == ErrInvalidConnectionState {
			c.log.WithFields(ErrField(err)).Debug("Health checker stopped.")
			return
		}

		consecutiveFailures++
		c.log.WithFields(LogFields{
			{"consecutiveFailures", consecutiveFailures},
			ErrField(err),
			{"failuresToClose", opts.FailuresToClose},
		}...).Warn("Failed active health check.")

		if consecutiveFailures >= opts.FailuresToClose {
			c.close(LogFields{
				{"reason", "health check failure"},
				ErrField(err),
			}...)
			return
		}
	}
}

// healthCheck will do periodic pings on the connection to check the state of the connection.
// We accept connID on the stack so can more easily debug panics or leaked goroutines.

healthCheck will do periodic pings on the connection to check the state of the connection . We accept connID on the stack so can more easily debug panics or leaked goroutines .


func (cb *ContextBuilder) SetTimeout(timeout time.Duration) *ContextBuilder {
	cb.Timeout = timeout
	return cb
}

func ( cb * ContextBuilder ) SetTimeout ( timeout time . Duration ) * ContextBuilder { cb . Timeout = timeout return cb }

// SetTimeout sets the timeout for the Context.

SetTimeout sets the timeout for the Context .


func (cb *ContextBuilder) AddHeader(key, value string) *ContextBuilder {
	if cb.Headers == nil {
		cb.Headers = map[string]string{key: value}
	} else {
		cb.Headers[key] = value
	}
	return cb
}

func ( cb * ContextBuilder ) AddHeader ( key , value string ) * ContextBuilder { if cb . Headers == nil { cb . Headers = map [ string ] string { key : value } } else { cb . Headers [ key ] = value } return cb }

// AddHeader adds a single application header to the Context.

AddHeader adds a single application header to the Context .


func (cb *ContextBuilder) SetHeaders(headers map[string]string) *ContextBuilder {
	cb.Headers = headers
	cb.replaceParentHeaders = true
	return cb
}

func ( cb * ContextBuilder ) SetHeaders ( headers map [ string ] string ) * ContextBuilder { cb . Headers = headers cb . replaceParentHeaders = true return cb }

// SetHeaders sets the application headers for this Context.
// If there is a ParentContext, its headers will be ignored after the call to this method.

SetHeaders sets the application headers for this Context . If there is a ParentContext its headers will be ignored after the call to this method .


func (cb *ContextBuilder) SetConnectTimeout(d time.Duration) *ContextBuilder {
	cb.ConnectTimeout = d
	return cb
}

func ( cb * ContextBuilder ) SetConnectTimeout ( d time . Duration ) * ContextBuilder { cb . ConnectTimeout = d return cb }

// SetConnectTimeout sets the ConnectionTimeout for this context.
// The context timeout applies to the whole call, while the connect
// timeout only applies to creating a new connection.

SetConnectTimeout sets the ConnectionTimeout for this context . The context timeout applies to the whole call while the connect timeout only applies to creating a new connection .


func (cb *ContextBuilder) SetRetryOptions(retryOptions *RetryOptions) *ContextBuilder {
	cb.RetryOptions = retryOptions
	return cb
}

func ( cb * ContextBuilder ) SetRetryOptions ( retryOptions * RetryOptions ) * ContextBuilder { cb . RetryOptions = retryOptions return cb }

// SetRetryOptions sets RetryOptions in the context.

SetRetryOptions sets RetryOptions in the context .


func (cb *ContextBuilder) SetTimeoutPerAttempt(timeoutPerAttempt time.Duration) *ContextBuilder {
	if cb.RetryOptions == nil {
		cb.RetryOptions = &RetryOptions{}
	}
	cb.RetryOptions.TimeoutPerAttempt = timeoutPerAttempt
	return cb
}

func ( cb * ContextBuilder ) SetTimeoutPerAttempt ( timeoutPerAttempt time . Duration ) * ContextBuilder { if cb . RetryOptions == nil { cb . RetryOptions = & RetryOptions { } } cb . RetryOptions . TimeoutPerAttempt = timeoutPerAttempt return cb }

// SetTimeoutPerAttempt sets TimeoutPerAttempt in RetryOptions.

SetTimeoutPerAttempt sets TimeoutPerAttempt in RetryOptions .


func (cb *ContextBuilder) SetParentContext(ctx context.Context) *ContextBuilder {
	cb.ParentContext = ctx
	return cb
}

func ( cb * ContextBuilder ) SetParentContext ( ctx context . Context ) * ContextBuilder { cb . ParentContext = ctx return cb }

// SetParentContext sets the parent for the Context.

SetParentContext sets the parent for the Context .


func (cb *ContextBuilder) Build() (ContextWithHeaders, context.CancelFunc) {
	params := &tchannelCtxParams{
		options:                 cb.CallOptions,
		call:                    cb.incomingCall,
		retryOptions:            cb.RetryOptions,
		connectTimeout:          cb.ConnectTimeout,
		hideListeningOnOutbound: cb.hideListeningOnOutbound,
		tracingDisabled:         cb.TracingDisabled,
	}

	parent := cb.ParentContext
	if parent == nil {
		parent = context.Background()
	} else if headerCtx, ok := parent.(headerCtx); ok {
		// Unwrap any headerCtx, since we'll be rewrapping anyway.
		parent = headerCtx.Context
	}

	var (
		ctx    context.Context
		cancel context.CancelFunc
	)
	// All contexts created must have a timeout, but if the parent
	// already has a timeout, and the user has not specified one, then we
	// can use context.WithCancel
	_, parentHasDeadline := parent.Deadline()
	if cb.Timeout == 0 && parentHasDeadline {
		ctx, cancel = context.WithCancel(parent)
	} else {
		ctx, cancel = context.WithTimeout(parent, cb.Timeout)
	}

	ctx = context.WithValue(ctx, contextKeyTChannel, params)
	return WrapWithHeaders(ctx, cb.getHeaders()), cancel
}

// Build returns a ContextWithHeaders that can be used to make calls.

Build returns a ContextWithHeaders that can be used to make calls .


func (c *CallOptions) overrideHeaders(headers transportHeaders) {
	if c.Format != "" {
		headers[ArgScheme] = c.Format.String()
	}
	if c.ShardKey != "" {
		headers[ShardKey] = c.ShardKey
	}
	if c.RoutingKey != "" {
		headers[RoutingKey] = c.RoutingKey
	}
	if c.RoutingDelegate != "" {
		headers[RoutingDelegate] = c.RoutingDelegate
	}
	if c.callerName != "" {
		headers[CallerName] = c.callerName
	}
}

func ( c * CallOptions ) overrideHeaders ( headers transportHeaders ) { if c . Format != " " { headers [ ArgScheme ] = c . Format . String ( ) } if c . ShardKey != " " { headers [ ShardKey ] = c . ShardKey } if c . RoutingKey != " " { headers [ RoutingKey ] = c . RoutingKey } if c . RoutingDelegate != " " { headers [ RoutingDelegate ] = c . RoutingDelegate } if c . callerName != " " { headers [ CallerName ] = c . callerName } }

// overrideHeaders sets headers if the call options contains non-default values.

overrideHeaders sets headers if the call options contains non - default values .


func (r ArgReadHelper) Read(bs *[]byte) error {
	return r.read(func() error {
		var err error
		*bs, err = ioutil.ReadAll(r.reader)
		return err
	})
}

func ( r ArgReadHelper ) Read ( bs * [ ] byte ) error { return r . read ( func ( ) error { var err error * bs , err = ioutil . ReadAll ( r . reader ) return err } ) }

// Read reads from the reader into the byte slice.

Read reads from the reader into the byte slice .


func (r ArgReadHelper) ReadJSON(data interface{}) error {
	return r.read(func() error {
		// TChannel allows for 0 length values (not valid JSON), so we use a bufio.Reader
		// to check whether data is of 0 length.
		reader := bufio.NewReader(r.reader)
		if _, err := reader.Peek(1); err == io.EOF {
			// If the data is 0 length, then we don't try to read anything.
			return nil
		} else if err != nil {
			return err
		}

		d := json.NewDecoder(reader)
		return d.Decode(data)
	})
}

// ReadJSON deserializes JSON from the underlying reader into data.

ReadJSON deserializes JSON from the underlying reader into data .


func NewArgWriter(writer io.WriteCloser, err error) ArgWriteHelper {
	return ArgWriteHelper{writer, err}
}

func NewArgWriter ( writer io . WriteCloser , err error ) ArgWriteHelper { return ArgWriteHelper { writer , err } }

// NewArgWriter wraps the result of calling ArgXWriter to provider a simpler
// interface for writing arguments.

NewArgWriter wraps the result of calling ArgXWriter to provider a simpler interface for writing arguments .


func (w ArgWriteHelper) Write(bs []byte) error {
	return w.write(func() error {
		_, err := w.writer.Write(bs)
		return err
	})
}

func ( w ArgWriteHelper ) Write ( bs [ ] byte ) error { return w . write ( func ( ) error { _ , err := w . writer . Write ( bs ) return err } ) }

// Write writes the given bytes to the underlying writer.

Write writes the given bytes to the underlying writer .


func (w ArgWriteHelper) WriteJSON(data interface{}) error {
	return w.write(func() error {
		e := json.NewEncoder(w.writer)
		return e.Encode(data)
	})
}

func ( w ArgWriteHelper ) WriteJSON ( data interface { } ) error { return w . write ( func ( ) error { e := json . NewEncoder ( w . writer ) return e . Encode ( data ) } ) }

// WriteJSON writes the given object as JSON.

WriteJSON writes the given object as JSON .


func Register(registrar tchannel.Registrar) {
	handler := func(ctx context.Context, call *tchannel.InboundCall) {
		req, err := thttp.ReadRequest(call)
		if err != nil {
			registrar.Logger().WithFields(
				tchannel.LogField{Key: "err", Value: err.Error()},
			).Warn("Failed to read HTTP request.")
			return
		}

		serveHTTP(req, call.Response())
	}
	registrar.Register(tchannel.HandlerFunc(handler), "_pprof")
}

func Register ( registrar tchannel . Registrar ) { handler := func ( ctx context . Context , call * tchannel . InboundCall ) { req , err := thttp . ReadRequest ( call ) if err != nil { registrar . Logger ( ) . WithFields ( tchannel . LogField { Key : " " , Value : err . Error ( ) } , ) . Warn ( " " ) return } serveHTTP ( req , call . Response ( ) ) } registrar . Register ( tchannel . HandlerFunc ( handler ) , " " ) }

// Register registers pprof endpoints on the given registrar under _pprof.
// The _pprof endpoint uses as-http and is a tunnel to the default serve mux.

Register registers pprof endpoints on the given registrar under _pprof . The _pprof endpoint uses as - http and is a tunnel to the default serve mux .


func (r *relayItems) Count() int {
	r.RLock()
	n := len(r.items) - int(r.tombs)
	r.RUnlock()
	return n
}

func ( r * relayItems ) Count ( ) int { r . RLock ( ) n := len ( r . items ) - int ( r . tombs ) r . RUnlock ( ) return n }

// Count returns the number of non-tombstone items in the relay.

Count returns the number of non - tombstone items in the relay .


func (r *relayItems) Get(id uint32) (relayItem, bool) {
	r.RLock()
	item, ok := r.items[id]
	r.RUnlock()

	return item, ok
}

func ( r * relayItems ) Get ( id uint32 ) ( relayItem , bool ) { r . RLock ( ) item , ok := r . items [ id ] r . RUnlock ( ) return item , ok }

// Get checks for a relay item by ID, returning the item and a bool indicating
// whether the item was found.

Get checks for a relay item by ID returning the item and a bool indicating whether the item was found .


func (r *relayItems) Add(id uint32, item relayItem) {
	r.Lock()
	r.items[id] = item
	r.Unlock()
}

func ( r * relayItems ) Add ( id uint32 , item relayItem ) { r . Lock ( ) r . items [ id ] = item r . Unlock ( ) }


func (r *relayItems) Entomb(id uint32, deleteAfter time.Duration) (relayItem, bool) {
	r.Lock()
	if r.tombs > _maxRelayTombs {
		r.Unlock()
		r.logger.WithFields(LogField{"id", id}).Warn("Too many tombstones, deleting relay item immediately.")
		return r.Delete(id)
	}
	item, ok := r.items[id]
	if !ok {
		r.Unlock()
		r.logger.WithFields(LogField{"id", id}).Warn("Can't find relay item to entomb.")
		return item, false
	}
	if item.tomb {
		r.Unlock()
		r.logger.WithFields(LogField{"id", id}).Warn("Re-entombing a tombstone.")
		return item, false
	}
	r.tombs++
	item.tomb = true
	r.items[id] = item
	r.Unlock()

	// TODO: We should be clearing these out in batches, rather than creating
	// individual timers for each item.
	time.AfterFunc(deleteAfter, func() { r.Delete(id) })
	return item, true
}

// Entomb sets the tomb bit on a relayItem and schedules a garbage collection. It
// returns the entombed item, along with a bool indicating whether we completed
// a relayed call.

Entomb sets the tomb bit on a relayItem and schedules a garbage collection . It returns the entombed item along with a bool indicating whether we completed a relayed call .


func NewRelayer(ch *Channel, conn *Connection) *Relayer {
	r := &Relayer{
		relayHost:    ch.RelayHost(),
		maxTimeout:   ch.relayMaxTimeout,
		localHandler: ch.relayLocal,
		outbound:     newRelayItems(conn.log.WithFields(LogField{"relayItems", "outbound"})),
		inbound:      newRelayItems(conn.log.WithFields(LogField{"relayItems", "inbound"})),
		peers:        ch.RootPeers(),
		conn:         conn,
		relayConn: &relay.Conn{
			RemoteAddr:        conn.conn.RemoteAddr().String(),
			RemoteProcessName: conn.RemotePeerInfo().ProcessName,
			IsOutbound:        conn.connDirection == outbound,
		},
		logger: conn.log,
	}
	r.timeouts = newRelayTimerPool(r.timeoutRelayItem, ch.relayTimerVerify)
	return r
}

func NewRelayer ( ch * Channel , conn * Connection ) * Relayer { r := & Relayer { relayHost : ch . RelayHost ( ) , maxTimeout : ch . relayMaxTimeout , localHandler : ch . relayLocal , outbound : newRelayItems ( conn . log . WithFields ( LogField { " " , " " } ) ) , inbound : newRelayItems ( conn . log . WithFields ( LogField { " " , " " } ) ) , peers : ch . RootPeers ( ) , conn : conn , relayConn : & relay . Conn { RemoteAddr : conn . conn . RemoteAddr ( ) . String ( ) , RemoteProcessName : conn . RemotePeerInfo ( ) . ProcessName , IsOutbound : conn . connDirection == outbound , } , logger : conn . log , } r . timeouts = newRelayTimerPool ( r . timeoutRelayItem , ch . relayTimerVerify ) return r }


func (r *Relayer) Relay(f *Frame) error {
	if f.messageType() != messageTypeCallReq {
		err := r.handleNonCallReq(f)
		if err == errUnknownID {
			// This ID may be owned by an outgoing call, so check the outbound
			// message exchange, and if it succeeds, then the frame has been
			// handled successfully.
			if err := r.conn.outbound.forwardPeerFrame(f); err == nil {
				return nil
			}
		}
		return err
	}
	return r.handleCallReq(newLazyCallReq(f))
}

// Relay is called for each frame that is read on the connection.

Relay is called for each frame that is read on the connection .


func (r *Relayer) Receive(f *Frame, fType frameType) (sent bool, failureReason string) {
	id := f.Header.ID

	// If we receive a response frame, we expect to find that ID in our outbound.
	// If we receive a request frame, we expect to find that ID in our inbound.
	items := r.receiverItems(fType)

	item, ok := items.Get(id)
	if !ok {
		r.logger.WithFields(
			LogField{"id", id},
		).Warn("Received a frame without a RelayItem.")
		return false, _relayErrorNotFound
	}

	finished := finishesCall(f)
	if item.tomb {
		// Call timed out, ignore this frame. (We've already handled stats.)
		// TODO: metrics for late-arriving frames.
		return true, ""
	}

	// call res frames don't include the OK bit, so we can't wait until the last
	// frame of a relayed RPC to determine if the call succeeded.
	if fType == responseFrame {
		// If we've gotten a response frame, we're the originating relayer and
		// should handle stats.
		if succeeded, failMsg := determinesCallSuccess(f); succeeded {
			item.call.Succeeded()
		} else if len(failMsg) > 0 {
			item.call.Failed(failMsg)
		}
	}
	select {
	case r.conn.sendCh <- f:
	default:
		// Buffer is full, so drop this frame and cancel the call.
		r.logger.WithFields(
			LogField{"id", id},
		).Warn("Dropping call due to slow connection.")

		items := r.receiverItems(fType)

		err := _relayErrorDestConnSlow
		// If we're dealing with a response frame, then the client is slow.
		if fType == responseFrame {
			err = _relayErrorSourceConnSlow
		}

		r.failRelayItem(items, id, err)
		return false, err
	}

	if finished {
		r.finishRelayItem(items, id)
	}

	return true, ""
}

// Receive receives frames intended for this connection.
// It returns whether the frame was sent and a reason for failure if it failed.

Receive receives frames intended for this connection . It returns whether the frame was sent and a reason for failure if it failed .


func (r *Relayer) handleNonCallReq(f *Frame) error {
	frameType := frameTypeFor(f)
	finished := finishesCall(f)

	// If we read a request frame, we need to use the outbound map to decide
	// the destination. Otherwise, we use the inbound map.
	items := r.outbound
	if frameType == responseFrame {
		items = r.inbound
	}

	item, ok := items.Get(f.Header.ID)
	if !ok {
		return errUnknownID
	}
	if item.tomb {
		// Call timed out, ignore this frame. (We've already handled stats.)
		// TODO: metrics for late-arriving frames.
		return nil
	}

	originalID := f.Header.ID
	f.Header.ID = item.remapID

	sent, failure := item.destination.Receive(f, frameType)
	if !sent {
		r.failRelayItem(items, originalID, failure)
		return nil
	}

	if finished {
		r.finishRelayItem(items, originalID)
	}
	return nil
}

// Handle all frames except messageTypeCallReq.

Handle all frames except messageTypeCallReq .


func (r *Relayer) addRelayItem(isOriginator bool, id, remapID uint32, destination *Relayer, ttl time.Duration, span Span, call RelayCall) relayItem {
	item := relayItem{
		call:        call,
		remapID:     remapID,
		destination: destination,
		span:        span,
	}

	items := r.inbound
	if isOriginator {
		items = r.outbound
	}
	item.timeout = r.timeouts.Get()
	items.Add(id, item)
	item.timeout.Start(ttl, items, id, isOriginator)
	return item
}

func ( r * Relayer ) addRelayItem ( isOriginator bool , id , remapID uint32 , destination * Relayer , ttl time . Duration , span Span , call RelayCall ) relayItem { item := relayItem { call : call , remapID : remapID , destination : destination , span : span , } items := r . inbound if isOriginator { items = r . outbound } item . timeout = r . timeouts . Get ( ) items . Add ( id , item ) item . timeout . Start ( ttl , items , id , isOriginator ) return item }

// addRelayItem adds a relay item to either outbound or inbound.

addRelayItem adds a relay item to either outbound or inbound .


func (r *Relayer) failRelayItem(items *relayItems, id uint32, failure string) {
	item, ok := items.Get(id)
	if !ok {
		items.logger.WithFields(LogField{"id", id}).Warn("Attempted to fail non-existent relay item.")
		return
	}

	// The call could time-out right as we entomb it, which would cause spurious
	// error logs, so ensure we can stop the timeout.
	if !item.timeout.Stop() {
		return
	}

	// Entomb it so that we don't get unknown exchange errors on further frames
	// for this call.
	item, ok = items.Entomb(id, _relayTombTTL)
	if !ok {
		return
	}
	if item.call != nil {
		// If the client is too slow, then there's no point sending an error frame.
		if failure != _relayErrorSourceConnSlow {
			r.conn.SendSystemError(id, item.span, errFrameNotSent)
		}
		item.call.Failed(failure)
		item.call.End()
	}

	r.decrementPending()
}

// failRelayItem tombs the relay item so that future frames for this call are not
// forwarded. We keep the relay item tombed, rather than delete it to ensure that
// future frames do not cause error logs.

failRelayItem tombs the relay item so that future frames for this call are not forwarded . We keep the relay item tombed rather than delete it to ensure that future frames do not cause error logs .


func WriteStruct(writer io.Writer, s thrift.TStruct) error {
	wp := getProtocolWriter(writer)
	err := s.Write(wp.protocol)
	thriftProtocolPool.Put(wp)
	return err
}

func WriteStruct ( writer io . Writer , s thrift . TStruct ) error { wp := getProtocolWriter ( writer ) err := s . Write ( wp . protocol ) thriftProtocolPool . Put ( wp ) return err }

// WriteStruct writes the given Thrift struct to a writer. It pools TProtocols.

WriteStruct writes the given Thrift struct to a writer . It pools TProtocols .


func ReadStruct(reader io.Reader, s thrift.TStruct) error {
	wp := getProtocolReader(reader)
	err := s.Read(wp.protocol)
	thriftProtocolPool.Put(wp)
	return err
}

func ReadStruct ( reader io . Reader , s thrift . TStruct ) error { wp := getProtocolReader ( reader ) err := s . Read ( wp . protocol ) thriftProtocolPool . Put ( wp ) return err }

// ReadStruct reads the given Thrift struct. It pools TProtocols.

ReadStruct reads the given Thrift struct . It pools TProtocols .


func EnsureEmpty(r io.Reader, stage string) error {
	buf := _bufPool.Get().(*[]byte)
	defer _bufPool.Put(buf)

	n, err := r.Read(*buf)
	if n > 0 {
		return fmt.Errorf("found unexpected bytes after %s, found (upto 128 bytes): %x", stage, (*buf)[:n])
	}
	if err == io.EOF {
		return nil
	}
	return err
}

func EnsureEmpty ( r io . Reader , stage string ) error { buf := _bufPool . Get ( ) . ( * [ ] byte ) defer _bufPool . Put ( buf ) n , err := r . Read ( * buf ) if n > 0 { return fmt . Errorf ( " " , stage , ( * buf ) [ : n ] ) } if err == io . EOF { return nil } return err }

// EnsureEmpty ensures that the specified reader is empty. If the reader is
// not empty, it returns an error with the specified stage in the message.

EnsureEmpty ensures that the specified reader is empty . If the reader is not empty it returns an error with the specified stage in the message .


func NewServer(optFns ...Option) Server {
	opts := getOptions(optFns)
	if opts.external {
		return newExternalServer(opts)
	}

	ch, err := tchannel.NewChannel(opts.svcName, &tchannel.ChannelOptions{
		Logger: tchannel.NewLevelLogger(tchannel.NewLogger(os.Stderr), tchannel.LogLevelWarn),
	})
	if err != nil {
		panic("failed to create channel: " + err.Error())
	}
	if err := ch.ListenAndServe("127.0.0.1:0"); err != nil {
		panic("failed to listen on port 0: " + err.Error())
	}

	s := &internalServer{
		ch:   ch,
		opts: opts,
	}

	tServer := thrift.NewServer(ch)
	tServer.Register(gen.NewTChanSecondServiceServer(handler{calls: &s.thriftCalls}))
	ch.Register(raw.Wrap(rawHandler{calls: &s.rawCalls}), "echo")

	if len(opts.advertiseHosts) > 0 {
		if err := s.Advertise(opts.advertiseHosts); err != nil {
			panic("failed to advertise: " + err.Error())
		}
	}

	return s
}

func NewServer ( optFns ... Option ) Server { opts := getOptions ( optFns ) if opts . external { return newExternalServer ( opts ) } ch , err := tchannel . NewChannel ( opts . svcName , & tchannel . ChannelOptions { Logger : tchannel . NewLevelLogger ( tchannel . NewLogger ( os . Stderr ) , tchannel . LogLevelWarn ) , } ) if err != nil { panic ( " " + err . Error ( ) ) } if err := ch . ListenAndServe ( " " ) ; err != nil { panic ( " " + err . Error ( ) ) } s := & internalServer { ch : ch , opts : opts , } tServer := thrift . NewServer ( ch ) tServer . Register ( gen . NewTChanSecondServiceServer ( handler { calls : & s . thriftCalls } ) ) ch . Register ( raw . Wrap ( rawHandler { calls : & s . rawCalls } ) , " " ) if len ( opts . advertiseHosts ) > 0 { if err := s . Advertise ( opts . advertiseHosts ) ; err != nil { panic ( " " + err . Error ( ) ) } } return s }

// NewServer returns a new Server that can recieve Thrift calls or raw calls.

NewServer returns a new Server that can recieve Thrift calls or raw calls .


func (s *internalServer) Advertise(hyperbahnHosts []string) error {
	config := hyperbahn.Configuration{InitialNodes: hyperbahnHosts}
	hc, err := hyperbahn.NewClient(s.ch, config, nil)
	if err != nil {
		panic("failed to setup Hyperbahn client: " + err.Error())
	}
	return hc.Advertise()
}

func ( s * internalServer ) Advertise ( hyperbahnHosts [ ] string ) error { config := hyperbahn . Configuration { InitialNodes : hyperbahnHosts } hc , err := hyperbahn . NewClient ( s . ch , config , nil ) if err != nil { panic ( " " + err . Error ( ) ) } return hc . Advertise ( ) }


func (c *Connection) handleCallReqContinue(frame *Frame) bool {
	if err := c.inbound.forwardPeerFrame(frame); err != nil {
		// If forward fails, it's due to a timeout. We can free this frame.
		return true
	}
	return false
}

// handleCallReqContinue handles the continuation of a call request, forwarding
// it to the request channel for that request, where it can be pulled during
// defragmentation

handleCallReqContinue handles the continuation of a call request forwarding it to the request channel for that request where it can be pulled during defragmentation


func (c *Connection) dispatchInbound(_ uint32, _ uint32, call *InboundCall, frame *Frame) {
	if call.log.Enabled(LogLevelDebug) {
		call.log.Debugf("Received incoming call for %s from %s", call.ServiceName(), c.remotePeerInfo)
	}

	if err := call.readMethod(); err != nil {
		call.log.WithFields(
			LogField{"remotePeer", c.remotePeerInfo},
			ErrField(err),
		).Error("Couldn't read method.")
		c.opts.FramePool.Release(frame)
		return
	}

	call.commonStatsTags["endpoint"] = call.methodString
	call.statsReporter.IncCounter("inbound.calls.recvd", call.commonStatsTags, 1)
	if span := call.response.span; span != nil {
		span.SetOperationName(call.methodString)
	}

	// TODO(prashant): This is an expensive way to check for cancellation. Use a heap for timeouts.
	go func() {
		select {
		case <-call.mex.ctx.Done():
			// checking if message exchange timedout or was cancelled
			// only two possible errors at this step:
			// context.DeadlineExceeded
			// context.Canceled
			if call.mex.ctx.Err() != nil {
				call.mex.inboundExpired()
			}
		case <-call.mex.errCh.c:
			if c.log.Enabled(LogLevelDebug) {
				call.log.Debugf("Wait for timeout/cancellation interrupted by error: %v", call.mex.errCh.err)
			}
			// when an exchange errors out, mark the exchange as expired
			// and call cancel so the server handler's context is canceled
			// TODO: move the cancel to the parent context at connnection level
			call.response.cancel()
			call.mex.inboundExpired()
		}
	}()

	c.handler.Handle(call.mex.ctx, call)
}

// dispatchInbound ispatches an inbound call to the appropriate handler


func (call *InboundCall) CallOptions() *CallOptions {
	return &CallOptions{
		callerName:      call.CallerName(),
		Format:          call.Format(),
		ShardKey:        call.ShardKey(),
		RoutingDelegate: call.RoutingDelegate(),
		RoutingKey:      call.RoutingKey(),
	}
}

func ( call * InboundCall ) CallOptions ( ) * CallOptions { return & CallOptions { callerName : call . CallerName ( ) , Format : call . Format ( ) , ShardKey : call . ShardKey ( ) , RoutingDelegate : call . RoutingDelegate ( ) , RoutingKey : call . RoutingKey ( ) , } }

// CallOptions returns a CallOptions struct suitable for forwarding a request.

CallOptions returns a CallOptions struct suitable for forwarding a request .


func (call *InboundCall) Response() *InboundCallResponse {
	if call.err != nil {
		// While reading Thrift, we cannot distinguish between malformed Thrift and other errors,
		// and so we may try to respond with a bad request. We should ensure that the response
		// is marked as failed if the request has failed so that we don't try to shutdown the exchange
		// a second time.
		call.response.err = call.err
	}
	return call.response
}

// Response provides access to the InboundCallResponse object which can be used
// to write back to the calling peer

Response provides access to the InboundCallResponse object which can be used to write back to the calling peer


func (response *InboundCallResponse) SendSystemError(err error) error {
	if response.err != nil {
		return response.err
	}
	// Fail all future attempts to read fragments
	response.state = reqResWriterComplete
	response.systemError = true
	response.doneSending()
	response.call.releasePreviousFragment()

	span := CurrentSpan(response.mex.ctx)

	return response.conn.SendSystemError(response.mex.msgID, *span, err)
}

// SendSystemError returns a system error response to the peer.  The call is considered
// complete after this method is called, and no further data can be written.

SendSystemError returns a system error response to the peer . The call is considered complete after this method is called and no further data can be written .


func (response *InboundCallResponse) SetApplicationError() error {
	if response.state > reqResWriterPreArg2 {
		return response.failed(errReqResWriterStateMismatch{
			state:         response.state,
			expectedState: reqResWriterPreArg2,
		})
	}
	response.applicationError = true
	return nil
}

func ( response * InboundCallResponse ) SetApplicationError ( ) error { if response . state > reqResWriterPreArg2 { return response . failed ( errReqResWriterStateMismatch { state : response . state , expectedState : reqResWriterPreArg2 , } ) } response . applicationError = true return nil }

// SetApplicationError marks the response as being an application error.  This method can
// only be called before any arguments have been sent to the calling peer.

SetApplicationError marks the response as being an application error . This method can only be called before any arguments have been sent to the calling peer .


func (response *InboundCallResponse) Arg2Writer() (ArgWriter, error) {
	if err := NewArgWriter(response.arg1Writer()).Write(nil); err != nil {
		return nil, err
	}
	return response.arg2Writer()
}

func ( response * InboundCallResponse ) Arg2Writer ( ) ( ArgWriter , error ) { if err := NewArgWriter ( response . arg1Writer ( ) ) . Write ( nil ) ; err != nil { return nil , err } return response . arg2Writer ( ) }

// Arg2Writer returns a WriteCloser that can be used to write the second argument.
// The returned writer must be closed once the write is complete.

Arg2Writer returns a WriteCloser that can be used to write the second argument . The returned writer must be closed once the write is complete .


func (response *InboundCallResponse) doneSending() {
	// TODO(prashant): Move this to when the message is actually being sent.
	now := response.timeNow()

	if span := response.span; span != nil {
		if response.applicationError || response.systemError {
			ext.Error.Set(span, true)
		}
		span.FinishWithOptions(opentracing.FinishOptions{FinishTime: now})
	}

	latency := now.Sub(response.calledAt)
	response.statsReporter.RecordTimer("inbound.calls.latency", response.commonStatsTags, latency)

	if response.systemError {
		// TODO(prashant): Report the error code type as per metrics doc and enable.
		// response.statsReporter.IncCounter("inbound.calls.system-errors", response.commonStatsTags, 1)
	} else if response.applicationError {
		response.statsReporter.IncCounter("inbound.calls.app-errors", response.commonStatsTags, 1)
	} else {
		response.statsReporter.IncCounter("inbound.calls.success", response.commonStatsTags, 1)
	}

	// Cancel the context since the response is complete.
	response.cancel()

	// The message exchange is still open if there are no errors, call shutdown.
	if response.err == nil {
		response.mex.shutdown()
	}
}

// doneSending shuts down the message exchange for this call.
// For incoming calls, the last message is sending the call response.

doneSending shuts down the message exchange for this call . For incoming calls the last message is sending the call response .


func newState(v *parser.Thrift, all map[string]parseState) *State {
	typedefs := make(map[string]*parser.Type)
	for k, v := range v.Typedefs {
		typedefs[k] = v.Type
	}

	// Enums are typedefs to an int64.
	i64Type := &parser.Type{Name: "i64"}
	for k := range v.Enums {
		typedefs[k] = i64Type
	}

	return &State{typedefs, nil, all}
}

func
newState
(
v
*
parser
.
Thrift
,
all
map
[
string
]
parseState
)
*
State
{
typedefs
:=
make
(
map
[
string
]
*
parser
.
Type
)
for
k
,
v
:=
range
v
.
Typedefs
{
typedefs
[
k
]
=
v
.
Type
}
// Enums are typedefs to an int64.
i64Type
:=
&
parser
.
Type
{
Name
:
"
"
}
for
k
:=
range
v
.
Enums
{
typedefs
[
k
]
=
i64Type
}
return
&
State
{
typedefs
,
,
all
}
}

// newState parses the type information for a parsed Thrift file and returns the state.

newState parses the type information for a parsed Thrift file and returns the state .


func (s *State) rootType(thriftType *parser.Type) *parser.Type {
	if state, newType, include := s.checkInclude(thriftType); include != nil {
		return state.rootType(newType)
	}

	if v, ok := s.typedefs[thriftType.Name]; ok {
		return s.rootType(v)
	}
	return thriftType
}

func ( s * State ) rootType ( thriftType * parser . Type ) * parser . Type { if state , newType , include := s . checkInclude ( thriftType ) ; include != nil { return state . rootType ( newType ) } if v , ok := s . typedefs [ thriftType . Name ] ; ok { return s . rootType ( v ) } return thriftType }

// rootType recurses through typedefs and returns the underlying type.

rootType recurses through typedefs and returns the underlying type .


func (s *State) checkInclude(thriftType *parser.Type) (*State, *parser.Type, *Include) {
	parts := strings.SplitN(thriftType.Name, ".", 2)
	if len(parts) < 2 {
		return nil, nil, nil
	}

	newType := *thriftType
	newType.Name = parts[1]

	include := s.includes[parts[0]]
	state := s.all[include.file]
	return state.global, &newType, include
}

func ( s * State ) checkInclude ( thriftType * parser . Type ) ( * State , * parser . Type , * Include ) { parts := strings . SplitN ( thriftType . Name , " " , 2 ) if len ( parts ) < 2 { return nil , nil , nil } newType := * thriftType newType . Name = parts [ 1 ] include := s . includes [ parts [ 0 ] ] state := s . all [ include . file ] return state . global , & newType , include }

// checkInclude will check if the type is an included type, and if so, return the
// state and type from the state for that file.

checkInclude will check if the type is an included type and if so return the state and type from the state for that file .


func (s *State) isResultPointer(thriftType *parser.Type) bool {
	_, basicGoType := thriftToGo[s.rootType(thriftType).Name]
	return !basicGoType
}

func ( s * State ) isResultPointer ( thriftType * parser . Type ) bool { _ , basicGoType := thriftToGo [ s . rootType ( thriftType ) . Name ] return ! basicGoType }

// isResultPointer returns whether the result for this method is a pointer.

isResultPointer returns whether the result for this method is a pointer .


func (s *State) goType(thriftType *parser.Type) string {
	return s.goTypePrefix("", thriftType)
}

func ( s * State ) goType ( thriftType * parser . Type ) string { return s . goTypePrefix ( " " , thriftType ) }

// goType returns the Go type name for the given thrift type.

goType returns the Go type name for the given thrift type .


func (s *State) goTypePrefix(prefix string, thriftType *parser.Type) string {
	switch thriftType.Name {
	case "binary":
		return "[]byte"
	case "list":
		return "[]" + s.goType(thriftType.ValueType)
	case "set":
		return "map[" + s.goType(thriftType.ValueType) + "]bool"
	case "map":
		return "map[" + s.goType(thriftType.KeyType) + "]" + s.goType(thriftType.ValueType)
	}

	// If the type is imported, then ignore the package.
	if state, newType, include := s.checkInclude(thriftType); include != nil {
		return state.goTypePrefix(include.Package()+".", newType)
	}

	// If the type is a direct Go type, use that.
	if goType, ok := thriftToGo[thriftType.Name]; ok {
		return goType
	}

	goThriftName := goPublicFieldName(thriftType.Name)
	goThriftName = prefix + goThriftName

	// Check if the type has a typedef to the direct Go type.
	rootType := s.rootType(thriftType)
	if _, ok := thriftToGo[rootType.Name]; ok {
		return goThriftName
	}
	if rootType.Name == "list" ||
		rootType.Name == "set" ||
		rootType.Name == "map" {
		return goThriftName
	}

	// If it's a typedef to another struct, then the typedef is defined as a pointer
	// so we do not want the pointer type here.
	if rootType != thriftType {
		return goThriftName
	}

	// If it's not a typedef for a basic type, we use a pointer.
	return "*" + goThriftName
}

// goTypePrefix returns the Go type name for the given thrift type with the prefix.

goTypePrefix returns the Go type name for the given thrift type with the prefix .


func NewContext(timeout time.Duration) (context.Context, context.CancelFunc) {
	return NewContextBuilder(timeout).Build()
}

func NewContext ( timeout time . Duration ) ( context . Context , context . CancelFunc ) { return NewContextBuilder ( timeout ) . Build ( ) }

// NewContext returns a new root context used to make TChannel requests.

NewContext returns a new root context used to make TChannel requests .


func newIncomingContext(call IncomingCall, timeout time.Duration) (context.Context, context.CancelFunc) {
	return NewContextBuilder(timeout).
		setIncomingCall(call).
		Build()
}

func newIncomingContext ( call IncomingCall , timeout time . Duration ) ( context . Context , context . CancelFunc ) { return NewContextBuilder ( timeout ) . setIncomingCall ( call ) . Build ( ) }

// newIncomingContext creates a new context for an incoming call with the given span.

newIncomingContext creates a new context for an incoming call with the given span .


func CurrentCall(ctx context.Context) IncomingCall {
	if params := getTChannelParams(ctx); params != nil {
		return params.call
	}
	return nil
}

func CurrentCall ( ctx context . Context ) IncomingCall { if params := getTChannelParams ( ctx ) ; params != nil { return params . call } return nil }

// CurrentCall returns the current incoming call, or nil if this is not an incoming call context.

CurrentCall returns the current incoming call or nil if this is not an incoming call context .


func New(seed int64) *rand.Rand {
	return rand.New(&lockedSource{src: rand.NewSource(seed)})
}

func New ( seed int64 ) * rand . Rand { return rand . New ( & lockedSource { src : rand . NewSource ( seed ) } ) }

// New returns a rand.Rand that is threadsafe.

New returns a rand . Rand that is threadsafe .


func (h *metaHandler) Health(ctx Context, req *meta.HealthRequest) (*meta.HealthStatus, error) {
	ok, message := h.healthFn(ctx, metaReqToReq(req))
	if message == "" {
		return &meta.HealthStatus{Ok: ok}, nil
	}
	return &meta.HealthStatus{Ok: ok, Message: &message}, nil
}

func ( h * metaHandler ) Health ( ctx Context , req * meta . HealthRequest ) ( * meta . HealthStatus , error ) { ok , message := h . healthFn ( ctx , metaReqToReq ( req ) ) if message == " " { return & meta . HealthStatus { Ok : ok } , nil } return & meta . HealthStatus { Ok : ok , Message : & message } , nil }

// Health returns true as default Health endpoint.

Health returns true as default Health endpoint .


func (c headerCtx) Headers() map[string]string {
	if h := c.headers(); h != nil {
		return h.reqHeaders
	}
	return nil
}

func ( c headerCtx ) Headers ( ) map [ string ] string { if h := c . headers ( ) ; h != nil { return h . reqHeaders } return nil }

// Headers gets application headers out of the context.

Headers gets application headers out of the context .


func (c headerCtx) ResponseHeaders() map[string]string {
	if h := c.headers(); h != nil {
		return h.respHeaders
	}
	return nil
}

func ( c headerCtx ) ResponseHeaders ( ) map [ string ] string { if h := c . headers ( ) ; h != nil { return h . respHeaders } return nil }

// ResponseHeaders returns the response headers.

ResponseHeaders returns the response headers .


func (c headerCtx) SetResponseHeaders(headers map[string]string) {
	if h := c.headers(); h != nil {
		h.respHeaders = headers
		return
	}
	panic("SetResponseHeaders called on ContextWithHeaders not created via WrapWithHeaders")
}

func ( c headerCtx ) SetResponseHeaders ( headers map [ string ] string ) { if h := c . headers ( ) ; h != nil { h . respHeaders = headers return } panic ( " " ) }

// SetResponseHeaders sets the response headers.

SetResponseHeaders sets the response headers .


func (c headerCtx) Child() ContextWithHeaders {
	var headersCopy headersContainer
	if h := c.headers(); h != nil {
		headersCopy = *h
	}

	return Wrap(context.WithValue(c.Context, contextKeyHeaders, &headersCopy))
}

func ( c headerCtx ) Child ( ) ContextWithHeaders { var headersCopy headersContainer if h := c . headers ( ) ; h != nil { headersCopy = * h } return Wrap ( context . WithValue ( c . Context , contextKeyHeaders , & headersCopy ) ) }

// Child creates a child context with a separate container for headers.

Child creates a child context with a separate container for headers .


func Wrap(ctx context.Context) ContextWithHeaders {
	hctx := headerCtx{Context: ctx}
	if h := hctx.headers(); h != nil {
		return hctx
	}

	// If there is no header container, we should create an empty one.
	return WrapWithHeaders(ctx, nil)
}

// Wrap wraps an existing context.Context into a ContextWithHeaders.
// If the underlying context has headers, they are preserved.

Wrap wraps an existing context . Context into a ContextWithHeaders . If the underlying context has headers they are preserved .


func WrapWithHeaders(ctx context.Context, headers map[string]string) ContextWithHeaders {
	h := &headersContainer{
		reqHeaders: headers,
	}
	newCtx := context.WithValue(ctx, contextKeyHeaders, h)
	return headerCtx{Context: newCtx}
}

func WrapWithHeaders ( ctx context . Context , headers map [ string ] string ) ContextWithHeaders { h := & headersContainer { reqHeaders : headers , } newCtx := context . WithValue ( ctx , contextKeyHeaders , h ) return headerCtx { Context : newCtx } }

// WrapWithHeaders returns a Context that can be used to make a call with request headers.
// If the parent `ctx` is already an instance of ContextWithHeaders, its existing headers
// will be ignored. In order to merge new headers with parent headers, use ContextBuilder.

WrapWithHeaders returns a Context that can be used to make a call with request headers . If the parent ctx is already an instance of ContextWithHeaders its existing headers will be ignored . In order to merge new headers with parent headers use ContextBuilder .


func WithoutHeaders(ctx context.Context) context.Context {
	return context.WithValue(context.WithValue(ctx, contextKeyTChannel, nil), contextKeyHeaders, nil)
}

func WithoutHeaders ( ctx context . Context ) context . Context { return context . WithValue ( context . WithValue ( ctx , contextKeyTChannel , nil ) , contextKeyHeaders , nil ) }

// WithoutHeaders hides any TChannel headers from the given context.

WithoutHeaders hides any TChannel headers from the given context .


func (e *errNotifier) Notify(err error) error {
	// The code should never try to Notify(nil).
	if err == nil {
		panic("cannot Notify with no error")
	}

	// There may be some sort of race where we try to notify the mex twice.
	if !e.notified.CAS(false, true) {
		return fmt.Errorf("cannot broadcast error: %v, already have: %v", err, e.err)
	}

	e.err = err
	close(e.c)
	return nil
}

// Notify will store the error and notify all waiters on c that there's an error.

Notify will store the error and notify all waiters on c that there s an error .


func (mex *messageExchange) forwardPeerFrame(frame *Frame) error {
	// We want a very specific priority here:
	// 1. Timeouts/cancellation (mex.ctx errors)
	// 2. Whether recvCh has buffer space (non-blocking select over mex.recvCh)
	// 3. Other mex errors (mex.errCh)
	// Which is why we check the context error only (instead of mex.checkError).
	// In the mex.errCh case, we do a non-blocking write to recvCh to prioritize it.
	if err := mex.ctx.Err(); err != nil {
		return GetContextError(err)
	}

	select {
	case mex.recvCh <- frame:
		return nil
	case <-mex.ctx.Done():
		// Note: One slow reader processing a large request could stall the connection.
		// If we see this, we need to increase the recvCh buffer size.
		return GetContextError(mex.ctx.Err())
	case <-mex.errCh.c:
		// Select will randomly choose a case, but we want to prioritize
		// sending a frame over the errCh. Try a non-blocking write.
		select {
		case mex.recvCh <- frame:
			return nil
		default:
		}
		return mex.errCh.err
	}
}

// forwardPeerFrame forwards a frame from a peer to the message exchange, where
// it can be pulled by whatever application thread is handling the exchange

forwardPeerFrame forwards a frame from a peer to the message exchange where it can be pulled by whatever application thread is handling the exchange


func (mex *messageExchange) recvPeerFrame() (*Frame, error) {
	// We have to check frames/errors in a very specific order here:
	// 1. Timeouts/cancellation (mex.ctx errors)
	// 2. Any pending frames (non-blocking select over mex.recvCh)
	// 3. Other mex errors (mex.errCh)
	// Which is why we check the context error only (instead of mex.checkError)e
	// In the mex.errCh case, we do a non-blocking read from recvCh to prioritize it.
	if err := mex.ctx.Err(); err != nil {
		return nil, GetContextError(err)
	}

	select {
	case frame := <-mex.recvCh:
		if err := mex.checkFrame(frame); err != nil {
			return nil, err
		}
		return frame, nil
	case <-mex.ctx.Done():
		return nil, GetContextError(mex.ctx.Err())
	case <-mex.errCh.c:
		// Select will randomly choose a case, but we want to prioritize
		// receiving a frame over errCh. Try a non-blocking read.
		select {
		case frame := <-mex.recvCh:
			if err := mex.checkFrame(frame); err != nil {
				return nil, err
			}
			return frame, nil
		default:
		}
		return nil, mex.errCh.err
	}
}

// recvPeerFrame waits for a new frame from the peer, or until the context
// expires or is cancelled

recvPeerFrame waits for a new frame from the peer or until the context expires or is cancelled


func (mex *messageExchange) recvPeerFrameOfType(msgType messageType) (*Frame, error) {
	frame, err := mex.recvPeerFrame()
	if err != nil {
		return nil, err
	}

	switch frame.Header.messageType {
	case msgType:
		return frame, nil

	case messageTypeError:
		// If we read an error frame, we can release it once we deserialize it.
		defer mex.framePool.Release(frame)

		errMsg := errorMessage{
			id: frame.Header.ID,
		}
		var rbuf typed.ReadBuffer
		rbuf.Wrap(frame.SizedPayload())
		if err := errMsg.read(&rbuf); err != nil {
			return nil, err
		}
		return nil, errMsg

	default:
		// TODO(mmihic): Should be treated as a protocol error
		mex.mexset.log.WithFields(
			LogField{"header", frame.Header},
			LogField{"expectedType", msgType},
			LogField{"expectedID", mex.msgID},
		).Warn("Received unexpected frame.")
		return nil, errUnexpectedFrameType
	}
}

// recvPeerFrameOfType waits for a new frame of a given type from the peer, failing
// if the next frame received is not of that type.
// If an error frame is returned, then the errorMessage is returned as the error.

recvPeerFrameOfType waits for a new frame of a given type from the peer failing if the next frame received is not of that type . If an error frame is returned then the errorMessage is returned as the error .


func (mex *messageExchange) shutdown() {
	// The reader and writer side can both hit errors and try to shutdown the mex,
	// so we ensure that it's only shut down once.
	if !mex.shutdownAtomic.CAS(false, true) {
		return
	}

	if mex.errChNotified.CAS(false, true) {
		mex.errCh.Notify(errMexShutdown)
	}

	mex.mexset.removeExchange(mex.msgID)
}

// shutdown shuts down the message exchange, removing it from the message
// exchange set so  that it cannot receive more messages from the peer.  The
// receive channel remains open, however, in case there are concurrent
// goroutines sending to it.

shutdown shuts down the message exchange removing it from the message exchange set so that it cannot receive more messages from the peer . The receive channel remains open however in case there are concurrent goroutines sending to it .


func newMessageExchangeSet(log Logger, name string) *messageExchangeSet {
	return &messageExchangeSet{
		name:             name,
		log:              log.WithFields(LogField{"exchange", name}),
		exchanges:        make(map[uint32]*messageExchange),
		expiredExchanges: make(map[uint32]struct{}),
	}
}

func newMessageExchangeSet ( log Logger , name string ) * messageExchangeSet { return & messageExchangeSet { name : name , log : log . WithFields ( LogField { " " , name } ) , exchanges : make ( map [ uint32 ] * messageExchange ) , expiredExchanges : make ( map [ uint32 ] struct { } ) , } }

// newMessageExchangeSet creates a new messageExchangeSet with a given name.

newMessageExchangeSet creates a new messageExchangeSet with a given name .


func (mexset *messageExchangeSet) addExchange(mex *messageExchange) error {
	if mexset.shutdown {
		return errMexSetShutdown
	}

	if _, ok := mexset.exchanges[mex.msgID]; ok {
		return errDuplicateMex
	}

	mexset.exchanges[mex.msgID] = mex
	return nil
}

func ( mexset * messageExchangeSet ) addExchange ( mex * messageExchange ) error { if mexset . shutdown { return errMexSetShutdown } if _ , ok := mexset . exchanges [ mex . msgID ] ; ok { return errDuplicateMex } mexset . exchanges [ mex . msgID ] = mex return nil }

// addExchange adds an exchange, it must be called with the mexset locked.

addExchange adds an exchange it must be called with the mexset locked .


func (mexset *messageExchangeSet) newExchange(ctx context.Context, framePool FramePool,
	msgType messageType, msgID uint32, bufferSize int) (*messageExchange, error) {
	if mexset.log.Enabled(LogLevelDebug) {
		mexset.log.Debugf("Creating new %s message exchange for [%v:%d]", mexset.name, msgType, msgID)
	}

	mex := &messageExchange{
		msgType:   msgType,
		msgID:     msgID,
		ctx:       ctx,
		recvCh:    make(chan *Frame, bufferSize),
		errCh:     newErrNotifier(),
		mexset:    mexset,
		framePool: framePool,
	}

	mexset.Lock()
	addErr := mexset.addExchange(mex)
	mexset.Unlock()

	if addErr != nil {
		logger := mexset.log.WithFields(
			LogField{"msgID", mex.msgID},
			LogField{"msgType", mex.msgType},
			LogField{"exchange", mexset.name},
		)
		if addErr == errMexSetShutdown {
			logger.Warn("Attempted to create new mex after mexset shutdown.")
		} else if addErr == errDuplicateMex {
			logger.Warn("Duplicate msg ID for active and new mex.")
		}

		return nil, addErr
	}

	mexset.onAdded()

	// TODO(mmihic): Put into a deadline ordered heap so we can garbage collected expired exchanges
	return mex, nil
}

// newExchange creates and adds a new message exchange to this set


func (mexset *messageExchangeSet) deleteExchange(msgID uint32) (found, timedOut bool) {
	if _, found := mexset.exchanges[msgID]; found {
		delete(mexset.exchanges, msgID)
		return true, false
	}

	if _, expired := mexset.expiredExchanges[msgID]; expired {
		delete(mexset.expiredExchanges, msgID)
		return false, true
	}

	return false, false
}

func ( mexset * messageExchangeSet ) deleteExchange ( msgID uint32 ) ( found , timedOut bool ) { if _ , found := mexset . exchanges [ msgID ] ; found { delete ( mexset . exchanges , msgID ) return true , false } if _ , expired := mexset . expiredExchanges [ msgID ] ; expired { delete ( mexset . expiredExchanges , msgID ) return false , true } return false , false }

// deleteExchange will delete msgID, and return whether it was found or whether it was
// timed out. This method must be called with the lock.

deleteExchange will delete msgID and return whether it was found or whether it was timed out . This method must be called with the lock .


func (mexset *messageExchangeSet) removeExchange(msgID uint32) {
	if mexset.log.Enabled(LogLevelDebug) {
		mexset.log.Debugf("Removing %s message exchange %d", mexset.name, msgID)
	}

	mexset.Lock()
	found, expired := mexset.deleteExchange(msgID)
	mexset.Unlock()

	if !found && !expired {
		mexset.log.WithFields(
			LogField{"msgID", msgID},
		).Error("Tried to remove exchange multiple times")
		return
	}

	// If the message exchange was found, then we perform clean up actions.
	// These clean up actions can only be run once per exchange.
	mexset.onRemoved()
}

// removeExchange removes a message exchange from the set, if it exists.

removeExchange removes a message exchange from the set if it exists .


func (mexset *messageExchangeSet) expireExchange(msgID uint32) {
	mexset.log.Debugf(
		"Removing %s message exchange %d due to timeout, cancellation or blackhole",
		mexset.name,
		msgID,
	)

	mexset.Lock()
	// TODO(aniketp): explore if cancel can be called everytime we expire an exchange
	found, expired := mexset.deleteExchange(msgID)
	if found || expired {
		// Record in expiredExchanges if we deleted the exchange.
		mexset.expiredExchanges[msgID] = struct{}{}
	}
	mexset.Unlock()

	if expired {
		mexset.log.WithFields(LogField{"msgID", msgID}).Info("Exchange expired already")
	}

	mexset.onRemoved()
}

// expireExchange is similar to removeExchange, but it marks the exchange as
// expired.

expireExchange is similar to removeExchange but it marks the exchange as expired .


func (mexset *messageExchangeSet) forwardPeerFrame(frame *Frame) error {
	if mexset.log.Enabled(LogLevelDebug) {
		mexset.log.Debugf("forwarding %s %s", mexset.name, frame.Header)
	}

	mexset.RLock()
	mex := mexset.exchanges[frame.Header.ID]
	mexset.RUnlock()

	if mex == nil {
		// This is ok since the exchange might have expired or been cancelled
		mexset.log.WithFields(
			LogField{"frameHeader", frame.Header.String()},
			LogField{"exchange", mexset.name},
		).Info("Received frame for unknown message exchange.")
		return nil
	}

	if err := mex.forwardPeerFrame(frame); err != nil {
		mexset.log.WithFields(
			LogField{"frameHeader", frame.Header.String()},
			LogField{"frameSize", frame.Header.FrameSize()},
			LogField{"exchange", mexset.name},
			ErrField(err),
		).Info("Failed to forward frame.")
		return err
	}

	return nil
}

// forwardPeerFrame forwards a frame from the peer to the appropriate message
// exchange

forwardPeerFrame forwards a frame from the peer to the appropriate message exchange


func (mexset *messageExchangeSet) copyExchanges() (shutdown bool, exchanges map[uint32]*messageExchange) {
	if mexset.shutdown {
		return true, nil
	}

	exchangesCopy := make(map[uint32]*messageExchange, len(mexset.exchanges))
	for k, mex := range mexset.exchanges {
		exchangesCopy[k] = mex
	}

	return false, exchangesCopy
}

func ( mexset * messageExchangeSet ) copyExchanges ( ) ( shutdown bool , exchanges map [ uint32 ] * messageExchange ) { if mexset . shutdown { return true , nil } exchangesCopy := make ( map [ uint32 ] * messageExchange , len ( mexset . exchanges ) ) for k , mex := range mexset . exchanges { exchangesCopy [ k ] = mex } return false , exchangesCopy }

// copyExchanges returns a copy of the exchanges if the exchange is active.
// The caller must lock the mexset.

copyExchanges returns a copy of the exchanges if the exchange is active . The caller must lock the mexset .


func (mexset *messageExchangeSet) stopExchanges(err error) {
	if mexset.log.Enabled(LogLevelDebug) {
		mexset.log.Debugf("stopping %v exchanges due to error: %v", mexset.count(), err)
	}

	mexset.Lock()
	shutdown, exchanges := mexset.copyExchanges()
	mexset.shutdown = true
	mexset.Unlock()

	if shutdown {
		mexset.log.Debugf("mexset has already been shutdown")
		return
	}

	for _, mex := range exchanges {
		// When there's a connection failure, we want to notify blocked callers that the
		// call will fail, but we don't want to shutdown the exchange as only the
		// arg reader/writer should shutdown the exchange. Otherwise, our guarantee
		// on sendChRefs that there's no references to sendCh is violated since
		// readers/writers could still have a reference to sendCh even though
		// we shutdown the exchange and called Done on sendChRefs.
		if mex.errChNotified.CAS(false, true) {
			mex.errCh.Notify(err)
		}
	}
}

// stopExchanges stops all message exchanges to unblock all waiters on the mex.
// This should only be called on connection failures.

stopExchanges stops all message exchanges to unblock all waiters on the mex . This should only be called on connection failures .


func NewFrame(payloadCapacity int) *Frame {
	f := &Frame{}
	f.buffer = make([]byte, payloadCapacity+FrameHeaderSize)
	f.Payload = f.buffer[FrameHeaderSize:]
	f.headerBuffer = f.buffer[:FrameHeaderSize]
	return f
}

func NewFrame ( payloadCapacity int ) * Frame { f := & Frame { } f . buffer = make ( [ ] byte , payloadCapacity + FrameHeaderSize ) f . Payload = f . buffer [ FrameHeaderSize : ] f . headerBuffer = f . buffer [ : FrameHeaderSize ] return f }

// NewFrame allocates a new frame with the given payload capacity


func (f *Frame) ReadBody(header []byte, r io.Reader) error {
	// Copy the header into the underlying buffer so we have an assembled frame
	// that can be directly forwarded.
	copy(f.buffer, header)

	// Parse the header into our typed struct.
	if err := f.Header.read(typed.NewReadBuffer(header)); err != nil {
		return err
	}

	switch payloadSize := f.Header.PayloadSize(); {
	case payloadSize > MaxFramePayloadSize:
		return fmt.Errorf("invalid frame size %v", f.Header.size)
	case payloadSize > 0:
		_, err := io.ReadFull(r, f.SizedPayload())
		return err
	default:
		// No payload to read
		return nil
	}
}

// ReadBody takes in a previously read frame header, and only reads in the body
// based on the size specified in the header. This allows callers to defer
// the frame allocation till the body needs to be read.

ReadBody takes in a previously read frame header and only reads in the body based on the size specified in the header . This allows callers to defer the frame allocation till the body needs to be read .


func (f *Frame) WriteOut(w io.Writer) error {
	var wbuf typed.WriteBuffer
	wbuf.Wrap(f.headerBuffer)

	if err := f.Header.write(&wbuf); err != nil {
		return err
	}

	fullFrame := f.buffer[:f.Header.FrameSize()]
	if _, err := w.Write(fullFrame); err != nil {
		return err
	}

	return nil
}

func ( f * Frame ) WriteOut ( w io . Writer ) error { var wbuf typed . WriteBuffer wbuf . Wrap ( f . headerBuffer ) if err := f . Header . write ( & wbuf ) ; err != nil { return err } fullFrame := f . buffer [ : f . Header . FrameSize ( ) ] if _ , err := w . Write ( fullFrame ) ; err != nil { return err } return nil }

// WriteOut writes the frame to the given io.Writer

WriteOut writes the frame to the given io . Writer


func (r RetryOn) CanRetry(err error) bool {
	if r == RetryNever {
		return false
	}
	if r == RetryDefault {
		r = RetryConnectionError
	}

	code := getErrCode(err)

	if code == ErrCodeBusy || code == ErrCodeDeclined {
		return true
	}
	// Never retry bad requests, since it will probably cause another bad request.
	if code == ErrCodeBadRequest {
		return false
	}

	switch r {
	case RetryConnectionError:
		return code == ErrCodeNetwork
	case RetryUnexpected:
		return code == ErrCodeUnexpected
	case RetryIdempotent:
		return true
	}

	return false
}

// CanRetry returns whether an error can be retried for the given retry option.

CanRetry returns whether an error can be retried for the given retry option .


func (rs *RequestState) HasRetries(err error) bool {
	if rs == nil {
		return false
	}
	rOpts := rs.retryOpts
	return rs.Attempt < rOpts.MaxAttempts && rOpts.RetryOn.CanRetry(err)
}

func ( rs * RequestState ) HasRetries ( err error ) bool { if rs == nil { return false } rOpts := rs . retryOpts return rs . Attempt < rOpts . MaxAttempts && rOpts . RetryOn . CanRetry ( err ) }

// HasRetries will return true if there are more retries left.

HasRetries will return true if there are more retries left .


func (rs *RequestState) SinceStart(now time.Time, fallback time.Duration) time.Duration {
	if rs == nil {
		return fallback
	}
	return now.Sub(rs.Start)
}

func ( rs * RequestState ) SinceStart ( now time . Time , fallback time . Duration ) time . Duration { if rs == nil { return fallback } return now . Sub ( rs . Start ) }

// SinceStart returns the time since the start of the request. If there is no request state,
// then the fallback is returned.

SinceStart returns the time since the start of the request . If there is no request state then the fallback is returned .


func (rs *RequestState) AddSelectedPeer(hostPort string) {
	if rs == nil {
		return
	}

	host := getHost(hostPort)
	if rs.SelectedPeers == nil {
		rs.SelectedPeers = map[string]struct{}{
			hostPort: {},
			host:     {},
		}
	} else {
		rs.SelectedPeers[hostPort] = struct{}{}
		rs.SelectedPeers[host] = struct{}{}
	}
}

func ( rs * RequestState ) AddSelectedPeer ( hostPort string ) { if rs == nil { return } host := getHost ( hostPort ) if rs . SelectedPeers == nil { rs . SelectedPeers = map [ string ] struct { } { hostPort : { } , host : { } , } } else { rs . SelectedPeers [ hostPort ] = struct { } { } rs . SelectedPeers [ host ] = struct { } { } } }

// AddSelectedPeer adds a given peer to the set of selected peers.

AddSelectedPeer adds a given peer to the set of selected peers .


func (ch *Channel) RunWithRetry(runCtx context.Context, f RetriableFunc) error {
	var err error

	opts := getRetryOptions(runCtx)
	rs := ch.getRequestState(opts)
	defer requestStatePool.Put(rs)

	for i := 0; i < opts.MaxAttempts; i++ {
		rs.Attempt++

		if opts.TimeoutPerAttempt == 0 {
			err = f(runCtx, rs)
		} else {
			attemptCtx, cancel := context.WithTimeout(runCtx, opts.TimeoutPerAttempt)
			err = f(attemptCtx, rs)
			cancel()
		}

		if err == nil {
			return nil
		}
		if !opts.RetryOn.CanRetry(err) {
			if ch.log.Enabled(LogLevelInfo) {
				ch.log.WithFields(ErrField(err)).Info("Failed after non-retriable error.")
			}
			return err
		}

		ch.log.WithFields(
			ErrField(err),
			LogField{"attempt", rs.Attempt},
			LogField{"maxAttempts", opts.MaxAttempts},
		).Info("Retrying request after retryable error.")
	}

	// Too many retries, return the last error
	return err
}

// RunWithRetry will take a function that makes the TChannel call, and will
// rerun it as specifed in the RetryOptions in the Context.

RunWithRetry will take a function that makes the TChannel call and will rerun it as specifed in the RetryOptions in the Context .


func (t ChecksumType) ChecksumSize() int {
	switch t {
	case ChecksumTypeNone:
		return 0
	case ChecksumTypeCrc32, ChecksumTypeCrc32C:
		return crc32.Size
	case ChecksumTypeFarmhash:
		return 4
	default:
		return 0
	}
}

func ( t ChecksumType ) ChecksumSize ( ) int { switch t { case ChecksumTypeNone : return 0 case ChecksumTypeCrc32 , ChecksumTypeCrc32C : return crc32 . Size case ChecksumTypeFarmhash : return 4 default : return 0 } }

// ChecksumSize returns the size in bytes of the checksum calculation


func (t ChecksumType) New() Checksum {
	s := t.pool().Get().(Checksum)
	s.Reset()
	return s
}

func ( t ChecksumType ) New ( ) Checksum { s := t . pool ( ) . Get ( ) . ( Checksum ) s . Reset ( ) return s }

// New creates a new Checksum of the given type


func parseTemplates(skipTChannel bool, templateFiles []string) ([]*Template, error) {
	var templates []*Template

	if !skipTChannel {
		templates = append(templates, &Template{
			name:     "tchan",
			template: template.Must(parseTemplate(tchannelTmpl)),
		})
	}

	for _, f := range templateFiles {
		t, err := parseTemplateFile(f)
		if err != nil {
			return nil, err
		}

		templates = append(templates, t)
	}

	return templates, nil
}

func parseTemplates ( skipTChannel bool , templateFiles [ ] string ) ( [ ] * Template , error ) { var templates [ ] * Template if ! skipTChannel { templates = append ( templates , & Template { name : " " , template : template . Must ( parseTemplate ( tchannelTmpl ) ) , } ) } for _ , f := range templateFiles { t , err := parseTemplateFile ( f ) if err != nil { return nil , err } templates = append ( templates , t ) } return templates , nil }

// parseTemplates returns a list of Templates that must be rendered given the template files.

parseTemplates returns a list of Templates that must be rendered given the template files .


func NewStringSliceFlag(name string, usage string) *[]string {
	var ss stringSliceFlag
	flag.Var(&ss, name, usage)
	return (*[]string)(&ss)
}

func NewStringSliceFlag ( name string , usage string ) * [ ] string { var ss stringSliceFlag flag . Var ( & ss , name , usage ) return ( * [ ] string ) ( & ss ) }

// NewStringSliceFlag creates a new string slice flag. The default value is always nil.

NewStringSliceFlag creates a new string slice flag . The default value is always nil .


func (t *Template) withStateFuncs(td TemplateData) *template.Template {
	return t.template.Funcs(map[string]interface{}{
		"goType": td.global.goType,
	})
}

func ( t * Template ) withStateFuncs ( td TemplateData ) * template . Template { return t . template . Funcs ( map [ string ] interface { } { " " : td . global . goType , } ) }

// withStateFuncs adds functions to the template that are dependent upon state.

withStateFuncs adds functions to the template that are dependent upon state .


func (ch *Channel) IntrospectOthers(opts *IntrospectionOptions) map[string][]ChannelInfo {
	if !opts.IncludeOtherChannels {
		return nil
	}

	channelMap.Lock()
	defer channelMap.Unlock()

	states := make(map[string][]ChannelInfo)
	for svc, channels := range channelMap.existing {
		channelInfos := make([]ChannelInfo, 0, len(channels))
		for _, otherChan := range channels {
			if ch == otherChan {
				continue
			}
			channelInfos = append(channelInfos, otherChan.ReportInfo(opts))
		}
		states[svc] = channelInfos
	}

	return states
}

func ( ch * Channel ) IntrospectOthers ( opts * IntrospectionOptions ) map [ string ] [ ] ChannelInfo { if ! opts . IncludeOtherChannels { return nil } channelMap . Lock ( ) defer channelMap . Unlock ( ) states := make ( map [ string ] [ ] ChannelInfo ) for svc , channels := range channelMap . existing { channelInfos := make ( [ ] ChannelInfo , 0 , len ( channels ) ) for _ , otherChan := range channels { if ch == otherChan { continue } channelInfos = append ( channelInfos , otherChan . ReportInfo ( opts ) ) } states [ svc ] = channelInfos } return states }

// IntrospectOthers returns the ChannelInfo for all other channels in this process.

IntrospectOthers returns the ChannelInfo for all other channels in this process .


func (ch *Channel) ReportInfo(opts *IntrospectionOptions) ChannelInfo {
	return ChannelInfo{
		ID:           ch.chID,
		CreatedStack: ch.createdStack,
		LocalPeer:    ch.PeerInfo(),
	}
}

func ( ch * Channel ) ReportInfo ( opts * IntrospectionOptions ) ChannelInfo { return ChannelInfo { ID : ch . chID , CreatedStack : ch . createdStack , LocalPeer : ch . PeerInfo ( ) , } }

// ReportInfo returns ChannelInfo for a channel.

ReportInfo returns ChannelInfo for a channel .


func (l *RootPeerList) IntrospectState(opts *IntrospectionOptions) map[string]PeerRuntimeState {
	return fromPeerList(l, opts)
}

func ( l * RootPeerList ) IntrospectState ( opts * IntrospectionOptions ) map [ string ] PeerRuntimeState { return fromPeerList ( l , opts ) }

// IntrospectState returns the runtime state of the


func (subChMap *subChannelMap) IntrospectState(opts *IntrospectionOptions) map[string]SubChannelRuntimeState {
	m := make(map[string]SubChannelRuntimeState)
	subChMap.RLock()
	for k, sc := range subChMap.subchannels {
		state := SubChannelRuntimeState{
			Service:  k,
			Isolated: sc.Isolated(),
		}
		if state.Isolated {
			state.IsolatedPeers = sc.Peers().IntrospectList(opts)
		}
		if hmap, ok := sc.handler.(*handlerMap); ok {
			state.Handler.Type = methodHandler
			methods := make([]string, 0, len(hmap.handlers))
			for k := range hmap.handlers {
				methods = append(methods, k)
			}
			sort.Strings(methods)
			state.Handler.Methods = methods
		} else {
			state.Handler.Type = overrideHandler
		}
		m[k] = state
	}
	subChMap.RUnlock()
	return m
}

func ( subChMap * subChannelMap ) IntrospectState ( opts * IntrospectionOptions ) map [ string ] SubChannelRuntimeState { m := make ( map [ string ] SubChannelRuntimeState ) subChMap . RLock ( ) for k , sc := range subChMap . subchannels { state := SubChannelRuntimeState { Service : k , Isolated : sc . Isolated ( ) , } if state . Isolated { state . IsolatedPeers = sc . Peers ( ) . IntrospectList ( opts ) } if hmap , ok := sc . handler . ( * handlerMap ) ; ok { state . Handler . Type = methodHandler methods := make ( [ ] string , 0 , len ( hmap . handlers ) ) for k := range hmap . handlers { methods = append ( methods , k ) } sort . Strings ( methods ) state . Handler . Methods = methods } else { state . Handler . Type = overrideHandler } m [ k ] = state } subChMap . RUnlock ( ) return m }

// IntrospectState returns the runtime state of the subchannels.

IntrospectState returns the runtime state of the subchannels .


func (p *Peer) IntrospectState(opts *IntrospectionOptions) PeerRuntimeState {
	p.RLock()
	defer p.RUnlock()

	return PeerRuntimeState{
		HostPort:            p.hostPort,
		InboundConnections:  getConnectionRuntimeState(p.inboundConnections, opts),
		OutboundConnections: getConnectionRuntimeState(p.outboundConnections, opts),
		ChosenCount:         p.chosenCount.Load(),
		SCCount:             p.scCount,
	}
}

func ( p * Peer ) IntrospectState ( opts * IntrospectionOptions ) PeerRuntimeState { p . RLock ( ) defer p . RUnlock ( ) return PeerRuntimeState { HostPort : p . hostPort , InboundConnections : getConnectionRuntimeState ( p . inboundConnections , opts ) , OutboundConnections : getConnectionRuntimeState ( p . outboundConnections , opts ) , ChosenCount : p . chosenCount . Load ( ) , SCCount : p . scCount , } }

// IntrospectState returns the runtime state for this peer.

IntrospectState returns the runtime state for this peer .


func (c *Connection) IntrospectState(opts *IntrospectionOptions) ConnectionRuntimeState {
	c.stateMut.RLock()
	defer c.stateMut.RUnlock()

	// TODO(prashantv): Add total number of health checks, and health check options.
	state := ConnectionRuntimeState{
		ID:               c.connID,
		ConnectionState:  c.state.String(),
		LocalHostPort:    c.conn.LocalAddr().String(),
		RemoteHostPort:   c.conn.RemoteAddr().String(),
		OutboundHostPort: c.outboundHP,
		RemotePeer:       c.remotePeerInfo,
		InboundExchange:  c.inbound.IntrospectState(opts),
		OutboundExchange: c.outbound.IntrospectState(opts),
		HealthChecks:     c.healthCheckHistory.asBools(),
		LastActivity:     c.lastActivity.Load(),
	}
	if c.relay != nil {
		state.Relayer = c.relay.IntrospectState(opts)
	}
	return state
}

// IntrospectState returns the runtime state for this connection.

IntrospectState returns the runtime state for this connection .