All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fluxtion.agrona.concurrent.broadcast.BroadcastTransmitter Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014-2024 Real Logic Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.fluxtion.agrona.concurrent.broadcast;

import com.fluxtion.agrona.BitUtil;
import com.fluxtion.agrona.DirectBuffer;
import com.fluxtion.agrona.concurrent.AtomicBuffer;
import com.fluxtion.agrona.concurrent.MemoryAccess;

import static com.fluxtion.agrona.concurrent.broadcast.BroadcastBufferDescriptor.*;
import static com.fluxtion.agrona.concurrent.broadcast.RecordDescriptor.*;

/**
 * Transmit messages via an underlying broadcast buffer to zero or more {@link BroadcastReceiver}s.
 * 

* Note: This class is not threadsafe. Only one transmitter is allowed per broadcast buffer. */ public class BroadcastTransmitter { private final AtomicBuffer buffer; private final int capacity; private final int maxMsgLength; private final int tailIntentCountIndex; private final int tailCounterIndex; private final int latestCounterIndex; /** * Construct a new broadcast transmitter based on an underlying {@link com.fluxtion.agrona.concurrent.AtomicBuffer}. * The underlying buffer must a power of 2 in size plus sufficient space * for the {@link BroadcastBufferDescriptor#TRAILER_LENGTH}. * * @param buffer via which messages will be exchanged. * @throws IllegalStateException if the buffer capacity is not a power of 2 * plus {@link BroadcastBufferDescriptor#TRAILER_LENGTH} in capacity. */ public BroadcastTransmitter(final AtomicBuffer buffer) { this.buffer = buffer; this.capacity = buffer.capacity() - TRAILER_LENGTH; checkCapacity(capacity); buffer.verifyAlignment(); this.maxMsgLength = calculateMaxMessageLength(capacity); this.tailIntentCountIndex = capacity + TAIL_INTENT_COUNTER_OFFSET; this.tailCounterIndex = capacity + TAIL_COUNTER_OFFSET; this.latestCounterIndex = capacity + LATEST_COUNTER_OFFSET; } /** * Get the capacity of the underlying broadcast buffer. * * @return the capacity of the underlying broadcast buffer. */ public int capacity() { return capacity; } /** * Get the maximum message length that can be transmitted for a buffer. * * @return the maximum message length that can be transmitted for a buffer. */ public int maxMsgLength() { return maxMsgLength; } /** * Transmit a message to {@link BroadcastReceiver}s via the broadcast buffer. * * @param msgTypeId type of the message to be transmitted. * @param srcBuffer containing the encoded message to be transmitted. * @param srcIndex srcIndex in the source buffer at which the encoded message begins. * @param length in bytes of the encoded message. * @throws IllegalArgumentException of the msgTypeId is not valid, * or if the message length is greater than {@link #maxMsgLength()}. */ public void transmit(final int msgTypeId, final DirectBuffer srcBuffer, final int srcIndex, final int length) { checkTypeId(msgTypeId); checkMessageLength(length); final AtomicBuffer buffer = this.buffer; long currentTail = buffer.getLong(tailCounterIndex); int recordOffset = (int)currentTail & (capacity - 1); final int recordLength = HEADER_LENGTH + length; final int recordLengthAligned = BitUtil.align(recordLength, RECORD_ALIGNMENT); final long newTail = currentTail + recordLengthAligned; final int toEndOfBuffer = capacity - recordOffset; if (toEndOfBuffer < recordLengthAligned) { signalTailIntent(buffer, newTail + toEndOfBuffer); insertPaddingRecord(buffer, recordOffset, toEndOfBuffer); currentTail += toEndOfBuffer; recordOffset = 0; } else { signalTailIntent(buffer, newTail); } buffer.putInt(lengthOffset(recordOffset), recordLength); buffer.putInt(typeOffset(recordOffset), msgTypeId); buffer.putBytes(msgOffset(recordOffset), srcBuffer, srcIndex, length); buffer.putLongOrdered(latestCounterIndex, currentTail); buffer.putLongOrdered(tailCounterIndex, currentTail + recordLengthAligned); } private void signalTailIntent(final AtomicBuffer buffer, final long newTail) { buffer.putLongOrdered(tailIntentCountIndex, newTail); MemoryAccess.releaseFence(); } private static void insertPaddingRecord(final AtomicBuffer buffer, final int recordOffset, final int length) { buffer.putInt(lengthOffset(recordOffset), length); buffer.putInt(typeOffset(recordOffset), PADDING_MSG_TYPE_ID); } private void checkMessageLength(final int length) { if (length > maxMsgLength) { throw new IllegalArgumentException( "encoded message exceeds maxMsgLength of " + maxMsgLength + ", length=" + length); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy