예제 #1
0
  /** {@inheritDoc} */
  public int size() {
    long headBefore;
    long tail;
    long headAfter = buffer.getLongVolatile(headPositionIndex);

    do {
      headBefore = headAfter;
      tail = buffer.getLongVolatile(tailPositionIndex);
      headAfter = buffer.getLongVolatile(headPositionIndex);
    } while (headAfter != headBefore);

    return (int) (tail - headAfter);
  }
예제 #2
0
  /**
   * Construct a new {@link RingBuffer} based on an underlying {@link AtomicBuffer}. The underlying
   * buffer must a power of 2 in size plus sufficient space for the {@link
   * RingBufferDescriptor#TRAILER_LENGTH}.
   *
   * @param buffer via which events will be exchanged.
   * @throws IllegalStateException if the buffer capacity is not a power of 2 plus {@link
   *     RingBufferDescriptor#TRAILER_LENGTH} in capacity.
   */
  public ManyToOneRingBuffer(final AtomicBuffer buffer) {
    this.buffer = buffer;
    checkCapacity(buffer.capacity());
    capacity = buffer.capacity() - RingBufferDescriptor.TRAILER_LENGTH;

    buffer.verifyAlignment();

    mask = capacity - 1;
    maxMsgLength = capacity / 8;
    tailPositionIndex = capacity + RingBufferDescriptor.TAIL_POSITION_OFFSET;
    headCachePositionIndex = capacity + RingBufferDescriptor.HEAD_CACHE_POSITION_OFFSET;
    headPositionIndex = capacity + RingBufferDescriptor.HEAD_POSITION_OFFSET;
    correlationIdCounterIndex = capacity + RingBufferDescriptor.CORRELATION_COUNTER_OFFSET;
    consumerHeartbeatIndex = capacity + RingBufferDescriptor.CONSUMER_HEARTBEAT_OFFSET;
  }
예제 #3
0
  private int claimCapacity(final AtomicBuffer buffer, final int requiredCapacity) {
    final int capacity = this.capacity;
    final int tailPositionIndex = this.tailPositionIndex;
    final int headCachePositionIndex = this.headCachePositionIndex;
    final int mask = this.mask;

    long head = buffer.getLongVolatile(headCachePositionIndex);

    long tail;
    int tailIndex;
    int padding;
    do {
      tail = buffer.getLongVolatile(tailPositionIndex);
      final int availableCapacity = capacity - (int) (tail - head);

      if (requiredCapacity > availableCapacity) {
        head = buffer.getLongVolatile(headPositionIndex);

        if (requiredCapacity > (capacity - (int) (tail - head))) {
          return INSUFFICIENT_CAPACITY;
        }

        buffer.putLongOrdered(headCachePositionIndex, head);
      }

      padding = 0;
      tailIndex = (int) tail & mask;
      final int toBufferEndLength = capacity - tailIndex;

      if (requiredCapacity > toBufferEndLength) {
        int headIndex = (int) head & mask;

        if (requiredCapacity > headIndex) {
          head = buffer.getLongVolatile(headPositionIndex);
          headIndex = (int) head & mask;
          if (requiredCapacity > headIndex) {
            return INSUFFICIENT_CAPACITY;
          }

          buffer.putLongOrdered(headCachePositionIndex, head);
        }

        padding = toBufferEndLength;
      }
    } while (!buffer.compareAndSetLong(tailPositionIndex, tail, tail + requiredCapacity + padding));

    if (0 != padding) {
      buffer.putLongOrdered(tailIndex, makeHeader(padding, PADDING_MSG_TYPE_ID));
      tailIndex = 0;
    }

    return tailIndex;
  }
예제 #4
0
  /** {@inheritDoc} */
  public int read(final MessageHandler handler, final int messageCountLimit) {
    int messagesRead = 0;

    final AtomicBuffer buffer = this.buffer;
    final long head = buffer.getLong(headPositionIndex);

    int bytesRead = 0;

    final int headIndex = (int) head & mask;
    final int contiguousBlockLength = capacity - headIndex;

    try {
      while ((bytesRead < contiguousBlockLength) && (messagesRead < messageCountLimit)) {
        final int recordIndex = headIndex + bytesRead;
        final long header = buffer.getLongVolatile(recordIndex);

        final int recordLength = recordLength(header);
        if (recordLength <= 0) {
          break;
        }

        bytesRead += align(recordLength, ALIGNMENT);

        final int messageTypeId = messageTypeId(header);
        if (PADDING_MSG_TYPE_ID == messageTypeId) {
          continue;
        }

        ++messagesRead;
        handler.onMessage(
            messageTypeId, buffer, recordIndex + HEADER_LENGTH, recordLength - HEADER_LENGTH);
      }
    } finally {
      if (bytesRead != 0) {
        buffer.setMemory(headIndex, bytesRead, (byte) 0);
        buffer.putLongOrdered(headPositionIndex, head + bytesRead);
      }
    }

    return messagesRead;
  }
예제 #5
0
  /** {@inheritDoc} */
  public boolean write(
      final int msgTypeId, final DirectBuffer srcBuffer, final int srcIndex, final int length) {
    checkTypeId(msgTypeId);
    checkMsgLength(length);

    boolean isSuccessful = false;

    final AtomicBuffer buffer = this.buffer;
    final int recordLength = length + HEADER_LENGTH;
    final int requiredCapacity = align(recordLength, ALIGNMENT);
    final int recordIndex = claimCapacity(buffer, requiredCapacity);

    if (INSUFFICIENT_CAPACITY != recordIndex) {
      buffer.putLongOrdered(recordIndex, makeHeader(-recordLength, msgTypeId));
      UnsafeAccess.UNSAFE.storeFence();

      buffer.putBytes(encodedMsgOffset(recordIndex), srcBuffer, srcIndex, length);
      buffer.putIntOrdered(lengthOffset(recordIndex), recordLength);

      isSuccessful = true;
    }

    return isSuccessful;
  }
예제 #6
0
  private static boolean scanBackToConfirmStillZeroed(
      final AtomicBuffer buffer, final int from, final int limit) {
    int i = from - ALIGNMENT;
    boolean allZeros = true;
    while (i >= limit) {
      if (0 != buffer.getIntVolatile(i)) {
        allZeros = false;
        break;
      }

      i -= ALIGNMENT;
    }

    return allZeros;
  }
예제 #7
0
  /** {@inheritDoc} */
  public boolean unblock() {
    final AtomicBuffer buffer = this.buffer;
    final int consumerIndex = (int) (buffer.getLongVolatile(headPositionIndex) & mask);
    final int producerIndex = (int) (buffer.getLongVolatile(tailPositionIndex) & mask);

    if (producerIndex == consumerIndex) {
      return false;
    }

    boolean unblocked = false;
    int length = buffer.getIntVolatile(consumerIndex);
    if (length < 0) {
      buffer.putLongOrdered(consumerIndex, makeHeader(-length, PADDING_MSG_TYPE_ID));
      unblocked = true;
    } else if (0 == length) {
      // go from (consumerIndex to producerIndex) or (consumerIndex to capacity)
      final int limit = producerIndex > consumerIndex ? producerIndex : buffer.capacity();
      int i = consumerIndex + ALIGNMENT;

      do {
        // read the top int of every long (looking for length aligned to 8=ALIGNMENT)
        length = buffer.getIntVolatile(i);
        if (0 != length) {
          if (scanBackToConfirmStillZeroed(buffer, i, consumerIndex)) {
            buffer.putLongOrdered(
                consumerIndex, makeHeader(i - consumerIndex, PADDING_MSG_TYPE_ID));
            unblocked = true;
          }

          break;
        }

        i += ALIGNMENT;
      } while (i < limit);
    }

    return unblocked;
  }
예제 #8
0
 /** {@inheritDoc} */
 public long consumerPosition() {
   return buffer.getLongVolatile(headPositionIndex);
 }
예제 #9
0
 /** {@inheritDoc} */
 public long producerPosition() {
   return buffer.getLongVolatile(tailPositionIndex);
 }
예제 #10
0
 /** {@inheritDoc} */
 public long consumerHeartbeatTime() {
   return buffer.getLongVolatile(consumerHeartbeatIndex);
 }
예제 #11
0
 /** {@inheritDoc} */
 public void consumerHeartbeatTime(final long time) {
   buffer.putLongOrdered(consumerHeartbeatIndex, time);
 }
예제 #12
0
 /** {@inheritDoc} */
 public long nextCorrelationId() {
   return buffer.getAndAddLong(correlationIdCounterIndex, 1);
 }