/**
   * Called from the {@link Receiver} thread to processing any pending loss of packets.
   *
   * @return number of work items processed.
   */
  int processPendingLoss() {
    int workCount = 0;
    final long changeNumber = endLossChange;

    if (changeNumber != lastLossChangeNumber) {
      final int termId = lossTermId;
      final int termOffset = lossTermOffset;
      final int length = lossLength;

      UNSAFE
          .loadFence(); // LoadLoad required so previous loads don't move past version check below.

      if (changeNumber == beginLossChange) {
        if (isReliable) {
          channelEndpoint.sendNakMessage(
              controlAddress, sessionId, streamId, termId, termOffset, length);
          nakMessagesSent.orderedIncrement();
        } else {
          final UnsafeBuffer termBuffer = termBuffers[indexByTerm(initialTermId, termId)];
          if (tryFillGap(rawLog.logMetaData(), termBuffer, termId, termOffset, length)) {
            lossGapFills.orderedIncrement();
          }
        }

        lastLossChangeNumber = changeNumber;
        workCount = 1;
      }
    }

    return workCount;
  }
  /**
   * Called from the {@link Receiver} thread to check for initiating an RTT measurement.
   *
   * @param now in nanoseconds
   * @return number of work items processed.
   */
  int initiateAnyRttMeasurements(final long now) {
    int workCount = 0;

    if (congestionControl.shouldMeasureRtt(now)) {
      channelEndpoint.sendRttMeasurement(controlAddress, sessionId, streamId, now, 0, true);
      workCount = 1;
    }

    return workCount;
  }
  /**
   * Called from the {@link Receiver} to send any pending Status Messages.
   *
   * @return number of work items processed.
   */
  int sendPendingStatusMessage() {
    int workCount = 0;

    if (ACTIVE == status) {
      final long changeNumber = endSmChange;

      if (changeNumber != lastSmChangeNumber) {
        final long smPosition = nextSmPosition;
        final int receiverWindowLength = nextSmReceiverWindowLength;

        UNSAFE.loadFence(); // LoadLoad required so previous loads don't move past version check
        // below.

        if (changeNumber == beginSmChange) {
          final int termId =
              computeTermIdFromPosition(smPosition, positionBitsToShift, initialTermId);
          final int termOffset = (int) smPosition & termLengthMask;

          channelEndpoint.sendStatusMessage(
              controlAddress,
              sessionId,
              streamId,
              termId,
              termOffset,
              receiverWindowLength,
              (byte) 0);

          statusMessagesSent.orderedIncrement();

          lastSmChangeNumber = changeNumber;
          workCount = 1;
        }
      }
    }

    return workCount;
  }
 /**
  * Remove this image from the {@link DataPacketDispatcher} so it will process no further packets
  * from the network. Called from the {@link Receiver} thread.
  */
 void removeFromDispatcher() {
   channelEndpoint.removePublicationImage(this);
 }
 /**
  * Get the string representation of the channel URI.
  *
  * @return the string representation of the channel URI.
  */
 public String channelUriString() {
   return channelEndpoint.originalUriString();
 }