TEST_F(SpscRbTest, shouldWriteVectorToEmptyBuffer)
{
    aeron_spsc_rb_t rb;
    size_t tail = 0;
    size_t tailIndex = 0;

    const int vec_len = 3;
    struct iovec vec[vec_len];
    vec[0].iov_base = m_buffer.data();
    vec[0].iov_len = 8;
    vec[1].iov_base = m_buffer.data() + (vec[0].iov_len);
    vec[1].iov_len = 7;
    vec[2].iov_base = m_buffer.data() + (vec[0].iov_len + vec[1].iov_len);
    vec[2].iov_len = 11;
    size_t length = vec[0].iov_len + vec[1].iov_len + vec[2].iov_len;

    size_t recordLength = length + AERON_RB_RECORD_HEADER_LENGTH;
    size_t alignedRecordLength = AERON_ALIGN(recordLength, AERON_RB_ALIGNMENT);

    ASSERT_EQ(aeron_spsc_rb_init(&rb, m_buffer.data(), m_buffer.size()), 0);

    ASSERT_EQ(aeron_spsc_rb_writev(&rb, MSG_TYPE_ID, vec, vec_len), AERON_RB_SUCCESS);

    aeron_rb_record_descriptor_t *record = (aeron_rb_record_descriptor_t *)(m_buffer.data() + tailIndex);

    EXPECT_EQ(record->length, (int32_t)recordLength);
    EXPECT_EQ(record->msg_type_id, (int32_t)MSG_TYPE_ID);
    EXPECT_EQ(rb.descriptor->tail_position, (int64_t)(tail + alignedRecordLength));
}
Exemple #2
0
aeron_rb_write_result_t aeron_mpsc_rb_write(
    volatile aeron_mpsc_rb_t *ring_buffer,
    int32_t msg_type_id,
    const void *msg,
    size_t length)
{
    const size_t record_length = length + AERON_RB_RECORD_HEADER_LENGTH;
    const size_t required_capacity = AERON_ALIGN(record_length, AERON_RB_ALIGNMENT);
    int32_t record_index = 0;
    aeron_rb_write_result_t result = AERON_RB_FULL;

    if (length > ring_buffer->max_message_length || AERON_RB_INVALID_MSG_TYPE_ID(msg_type_id))
    {
        return AERON_RB_ERROR;
    }

    record_index = aeron_mpsc_rb_claim_capacity(ring_buffer, required_capacity);

    if (-1 != record_index)
    {
        aeron_rb_record_descriptor_t *record_header = (aeron_rb_record_descriptor_t *)(ring_buffer->buffer + record_index);
        record_header->msg_type_id = msg_type_id;
        AERON_PUT_ORDERED(record_header->length, -record_length);
        memcpy(ring_buffer->buffer + AERON_RB_MESSAGE_OFFSET(record_index), msg, length);
        AERON_PUT_ORDERED(record_header->length, record_length);

        result = AERON_RB_SUCCESS;
    }

    return result;
}
TEST_F(SpscRbTest, shouldLimitReadOfMessages)
{
    aeron_spsc_rb_t rb;
    size_t length = 8;
    size_t head = 0;
    size_t recordLength = length + AERON_RB_RECORD_HEADER_LENGTH;
    size_t alignedRecordLength = AERON_ALIGN(recordLength, AERON_RB_ALIGNMENT);
    size_t tail = alignedRecordLength * 2;

    ASSERT_EQ(aeron_spsc_rb_init(&rb, m_buffer.data(), m_buffer.size()), 0);
    rb.descriptor->head_position = (int64_t)head;
    rb.descriptor->tail_position = (int64_t)tail;

    aeron_rb_record_descriptor_t *record;

    record = (aeron_rb_record_descriptor_t *)(rb.buffer);
    record->msg_type_id = (int32_t)MSG_TYPE_ID;
    record->length = (int32_t)recordLength;

    record = (aeron_rb_record_descriptor_t *)(rb.buffer + alignedRecordLength);
    record->msg_type_id = (int32_t)MSG_TYPE_ID;
    record->length = (int32_t)recordLength;

    size_t timesCalled = 0;
    const size_t messagesRead = aeron_spsc_rb_read(&rb, countTimesAsSizeT, &timesCalled, 1);

    EXPECT_EQ(messagesRead, (size_t)1);
    EXPECT_EQ(timesCalled, (size_t)1);
    EXPECT_EQ(rb.descriptor->head_position, (int64_t)(head + alignedRecordLength));

    for (size_t i = 0; i < AERON_RB_ALIGNMENT; i += 4)
    {
        EXPECT_EQ(*((int32_t *)(rb.buffer + i)), 0) << "buffer has not been zeroed between indexes " << i << "-" << i+3;
    }
}
TEST_F(SpscRbTest, shouldRejectWriteVectorWhenInsufficientSpace)
{
    aeron_spsc_rb_t rb;

    const int vec_len = 3;
    struct iovec vec[vec_len];
    vec[0].iov_base = m_buffer.data();
    vec[0].iov_len = 1;
    vec[1].iov_base = m_buffer.data() + (vec[0].iov_len);
    vec[1].iov_len = 1;
    vec[2].iov_base = m_buffer.data() + (vec[0].iov_len + vec[1].iov_len);
    vec[2].iov_len = 98;
    size_t length = vec[0].iov_len + vec[1].iov_len + vec[2].iov_len;

    size_t head = 0;
    size_t tail = head + (CAPACITY - AERON_ALIGN(length - AERON_RB_ALIGNMENT, AERON_RB_ALIGNMENT));

    ASSERT_EQ(aeron_spsc_rb_init(&rb, m_buffer.data(), m_buffer.size()), 0);
    rb.descriptor->head_position = (int64_t)head;
    rb.descriptor->tail_position = (int64_t)tail;

    ASSERT_EQ(aeron_spsc_rb_writev(&rb, MSG_TYPE_ID, vec, vec_len), AERON_RB_FULL);

    EXPECT_EQ(rb.descriptor->tail_position, (int64_t)tail);
}
TEST_F(BroadcastTransmitterTest, shouldApplyPaddingWhenInsufficientSpaceAtEndOfBuffer)
{
    aeron_broadcast_transmitter_t transmitter;
    size_t tail = CAPACITY - AERON_BROADCAST_RECORD_ALIGNMENT;
    size_t record_offset = tail;
    size_t length = AERON_BROADCAST_RECORD_ALIGNMENT + 8;
    size_t recordLength = length + AERON_BROADCAST_RECORD_HEADER_LENGTH;
    size_t alignedRecordLength = AERON_ALIGN(recordLength, AERON_BROADCAST_RECORD_ALIGNMENT);
    const size_t toEndOfBuffer = CAPACITY - record_offset;

    ASSERT_EQ(aeron_broadcast_transmitter_init(&transmitter, m_buffer.data(), m_buffer.size()), 0);

    transmitter.descriptor->tail_counter = (int64_t)tail;

    EXPECT_EQ(aeron_broadcast_transmitter_transmit(&transmitter, MSG_TYPE_ID, m_srcBuffer.data(), length), 0);

    aeron_broadcast_record_descriptor_t *record =
        (aeron_broadcast_record_descriptor_t *)(m_buffer.data() + record_offset);

    EXPECT_EQ(transmitter.descriptor->tail_intent_counter, (int64_t)(tail + alignedRecordLength + toEndOfBuffer));
    EXPECT_EQ(record->length, (int32_t)toEndOfBuffer);
    EXPECT_EQ(record->msg_type_id, AERON_BROADCAST_PADDING_MSG_TYPE_ID);

    tail += toEndOfBuffer;
    record_offset = 0;

    record = (aeron_broadcast_record_descriptor_t *)(m_buffer.data() + record_offset);

    EXPECT_EQ(record->length, (int32_t)recordLength);
    EXPECT_EQ(record->msg_type_id, (int32_t)MSG_TYPE_ID);
    EXPECT_EQ(transmitter.descriptor->latest_counter, (int64_t)tail);
    EXPECT_EQ(transmitter.descriptor->tail_counter, (int64_t)(tail + alignedRecordLength));
}
Exemple #6
0
size_t aeron_mpsc_rb_read(
    volatile aeron_mpsc_rb_t *ring_buffer,
    aeron_rb_handler_t handler,
    void *clientd,
    size_t message_count_limit)
{
    const int64_t head = ring_buffer->descriptor->head_position;
    const size_t head_index = (int32_t)head & (ring_buffer->capacity - 1);
    const size_t contiguous_block_length = ring_buffer->capacity - head_index;
    size_t messages_read = 0;
    size_t bytes_read = 0;

    while ((bytes_read < contiguous_block_length) && (messages_read < message_count_limit))
    {
        aeron_rb_record_descriptor_t *header = NULL;
        const size_t record_index = head_index + bytes_read;
        int32_t record_length = 0;
        int32_t msg_type_id = 0;

        header = (aeron_rb_record_descriptor_t *)(ring_buffer->buffer + record_index);
        AERON_GET_VOLATILE(record_length, header->length);

        if (record_length <= 0)
        {
            break;
        }

        bytes_read += AERON_ALIGN(record_length, AERON_RB_ALIGNMENT);
        msg_type_id = header->msg_type_id;

        if (AERON_RB_PADDING_MSG_TYPE_ID == msg_type_id)
        {
            continue;
        }

        ++messages_read;
        handler(
            msg_type_id,
            ring_buffer->buffer + AERON_RB_MESSAGE_OFFSET(record_index),
            record_length - AERON_RB_RECORD_HEADER_LENGTH,
            clientd);

    }

    if (0 != bytes_read)
    {
        memset(ring_buffer->buffer + head_index, 0, bytes_read);
        AERON_PUT_ORDERED(ring_buffer->descriptor->head_position, head + bytes_read);
    }

    return messages_read;
}
TEST_F(SpscRbTest, shouldRejectWriteWhenInsufficientSpace)
{
    aeron_spsc_rb_t rb;
    size_t length = 100;
    size_t head = 0;
    size_t tail = head + (CAPACITY - AERON_ALIGN(length - AERON_RB_ALIGNMENT, AERON_RB_ALIGNMENT));

    ASSERT_EQ(aeron_spsc_rb_init(&rb, m_buffer.data(), m_buffer.size()), 0);
    rb.descriptor->head_position = (int64_t)head;
    rb.descriptor->tail_position = (int64_t)tail;

    ASSERT_EQ(aeron_spsc_rb_write(&rb, MSG_TYPE_ID, m_srcBuffer.data(), length), AERON_RB_FULL);

    EXPECT_EQ(rb.descriptor->tail_position, (int64_t)tail);
}
int aeron_broadcast_transmitter_transmit(
    volatile aeron_broadcast_transmitter_t *transmitter,
    int32_t msg_type_id,
    const void *msg,
    size_t length)
{
    if (length > transmitter->max_message_length || AERON_BROADCAST_INVALID_MSG_TYPE_ID(msg_type_id))
    {
        return -1;
    }

    int64_t current_tail = transmitter->descriptor->tail_counter;
    size_t record_offset = (uint32_t)current_tail & (transmitter->capacity - 1);
    const size_t record_length = length + AERON_BROADCAST_RECORD_HEADER_LENGTH;
    const size_t aligned_record_length = AERON_ALIGN(record_length, AERON_BROADCAST_RECORD_ALIGNMENT);
    const int64_t new_tail = current_tail + (int64_t)aligned_record_length;

    const size_t to_end_of_buffer = (uint32_t)transmitter->capacity - record_offset;

    if (to_end_of_buffer < aligned_record_length)
    {
        signal_tail_intent(transmitter->descriptor, new_tail + (int64_t)to_end_of_buffer);
        insert_padding_record(
            (aeron_broadcast_record_descriptor_t *)(transmitter->buffer + record_offset), (int32_t)to_end_of_buffer);

        current_tail += to_end_of_buffer;
        record_offset = 0;
    }
    else
    {
        signal_tail_intent(transmitter->descriptor, new_tail);
    }

    aeron_broadcast_record_descriptor_t *record =
        (aeron_broadcast_record_descriptor_t *)(transmitter->buffer + record_offset);

    record->length = (int32_t)record_length;
    record->msg_type_id = msg_type_id;

    memcpy(transmitter->buffer + record_offset + AERON_BROADCAST_RECORD_HEADER_LENGTH, msg, length);

    transmitter->descriptor->latest_counter = current_tail;
    AERON_PUT_ORDERED(transmitter->descriptor->tail_counter, current_tail + aligned_record_length);

    return 0;
}
size_t aeron_error_log_read(
    const uint8_t *buffer,
    size_t buffer_size,
    aeron_error_log_reader_func_t reader,
    void *clientd,
    int64_t since_timestamp)
{
    size_t entries = 0;
    size_t offset = 0;

    while (offset < buffer_size)
    {
        aeron_error_log_entry_t *entry = (aeron_error_log_entry_t *)(buffer + offset);
        int32_t length = 0;

        AERON_GET_VOLATILE(length, entry->length);

        if (0 == length)
        {
            break;
        }

        int64_t last_observation_timestamp = 0;
        AERON_GET_VOLATILE(last_observation_timestamp, entry->last_observation_timestamp);

        if (last_observation_timestamp >= since_timestamp)
        {
            ++entries;

            reader(
                entry->observation_count,
                entry->first_observation_timestamp,
                last_observation_timestamp,
                (const char *)(buffer + offset + AERON_ERROR_LOG_HEADER_LENGTH),
                length - AERON_ERROR_LOG_HEADER_LENGTH,
                clientd);
        }

        offset += AERON_ALIGN(length, AERON_ERROR_LOG_RECORD_ALIGNMENT);
    }

    return entries;
}
TEST_F(SpscRbTest, shouldWriteToEmptyBuffer)
{
    aeron_spsc_rb_t rb;
    size_t tail = 0;
    size_t tailIndex = 0;
    size_t length = 8;
    size_t recordLength = length + AERON_RB_RECORD_HEADER_LENGTH;
    size_t alignedRecordLength = AERON_ALIGN(recordLength, AERON_RB_ALIGNMENT);

    ASSERT_EQ(aeron_spsc_rb_init(&rb, m_buffer.data(), m_buffer.size()), 0);

    ASSERT_EQ(aeron_spsc_rb_write(&rb, MSG_TYPE_ID, m_srcBuffer.data(), length), AERON_RB_SUCCESS);

    aeron_rb_record_descriptor_t *record = (aeron_rb_record_descriptor_t *)(m_buffer.data() + tailIndex);

    EXPECT_EQ(record->length, (int32_t)recordLength);
    EXPECT_EQ(record->msg_type_id, (int32_t)MSG_TYPE_ID);
    EXPECT_EQ(rb.descriptor->tail_position, (int64_t)(tail + alignedRecordLength));
}
TEST_F(BroadcastTransmitterTest, shouldTransmitIntoEmptyBuffer)
{
    aeron_broadcast_transmitter_t transmitter;
    size_t tail = 0;
    size_t record_offset = tail;
    size_t length = 8;
    size_t recordLength = length + AERON_BROADCAST_RECORD_HEADER_LENGTH;
    size_t alignedRecordLength = AERON_ALIGN(recordLength, AERON_BROADCAST_RECORD_ALIGNMENT);

    ASSERT_EQ(aeron_broadcast_transmitter_init(&transmitter, m_buffer.data(), m_buffer.size()), 0);

    EXPECT_EQ(aeron_broadcast_transmitter_transmit(&transmitter, MSG_TYPE_ID, m_srcBuffer.data(), length), 0);

    aeron_broadcast_record_descriptor_t *record =
        (aeron_broadcast_record_descriptor_t *)(m_buffer.data() + record_offset);

    EXPECT_EQ(transmitter.descriptor->tail_intent_counter, (int64_t)(tail + alignedRecordLength));
    EXPECT_EQ(record->length, (int32_t)recordLength);
    EXPECT_EQ(record->msg_type_id, (int32_t)MSG_TYPE_ID);
    EXPECT_EQ(transmitter.descriptor->latest_counter, (int64_t)tail);
    EXPECT_EQ(transmitter.descriptor->tail_counter, (int64_t)(tail + alignedRecordLength));
}
TEST_F(SpscRbTest, shouldNotReadSingleMessagePartWayThroughWriting)
{
    aeron_spsc_rb_t rb;
    size_t length = 8;
    size_t head = 0;
    size_t recordLength = length + AERON_RB_RECORD_HEADER_LENGTH;
    size_t alignedRecordLength = AERON_ALIGN(recordLength, AERON_RB_ALIGNMENT);
    size_t endTail = alignedRecordLength;

    ASSERT_EQ(aeron_spsc_rb_init(&rb, m_buffer.data(), m_buffer.size()), 0);
    rb.descriptor->head_position = (int64_t)head;
    rb.descriptor->tail_position = (int64_t)endTail;

    aeron_rb_record_descriptor_t *record = (aeron_rb_record_descriptor_t *)(rb.buffer);
    record->msg_type_id = (int32_t)MSG_TYPE_ID;
    record->length = -((int32_t)recordLength);

    size_t timesCalled = 0;
    const size_t messagesRead = aeron_spsc_rb_read(&rb, countTimesAsSizeT, &timesCalled, 10);

    EXPECT_EQ(messagesRead, (size_t)0);
    EXPECT_EQ(timesCalled, (size_t)0);
    EXPECT_EQ(rb.descriptor->head_position, (int64_t)head);
}
TEST_F(SpscRbTest, shouldInsertPaddingRecordPlusMessageOnBufferWrapWithHeadEqualToTail)
{
    aeron_spsc_rb_t rb;
    size_t length = 100;
    size_t recordLength = length + AERON_RB_RECORD_HEADER_LENGTH;
    size_t alignedRecordLength = AERON_ALIGN(recordLength, AERON_RB_ALIGNMENT);
    size_t tail = CAPACITY - AERON_RB_ALIGNMENT;
    size_t head = tail;

    ASSERT_EQ(aeron_spsc_rb_init(&rb, m_buffer.data(), m_buffer.size()), 0);
    rb.descriptor->head_position = (int64_t)head;
    rb.descriptor->tail_position = (int64_t)tail;

    ASSERT_EQ(aeron_spsc_rb_write(&rb, MSG_TYPE_ID, m_srcBuffer.data(), length), AERON_RB_SUCCESS);

    aeron_rb_record_descriptor_t *record = (aeron_rb_record_descriptor_t *)(rb.buffer + tail);
    EXPECT_EQ(record->msg_type_id, (int32_t)AERON_RB_PADDING_MSG_TYPE_ID);
    EXPECT_EQ(record->length, (int32_t)AERON_RB_ALIGNMENT);

    record = (aeron_rb_record_descriptor_t *)(rb.buffer);
    EXPECT_EQ(record->msg_type_id, (int32_t)MSG_TYPE_ID);
    EXPECT_EQ(record->length, (int32_t)recordLength);
    EXPECT_EQ(rb.descriptor->tail_position, (int64_t)(tail + alignedRecordLength + AERON_RB_ALIGNMENT));
}
Exemple #14
0
static aeron_distinct_observation_t *aeron_distinct_error_log_new_observation(
    aeron_distinct_error_log_t *log,
    size_t existing_num_observations,
    int64_t timestamp,
    int error_code,
    const char *description,
    const char *message)
{
    size_t num_observations = atomic_load(&log->observations_pimpl->num_observations);
    aeron_distinct_observation_t *observations = atomic_load(&log->observations_pimpl->observations);
    aeron_distinct_observation_t *observation = NULL;

    if ((observation = aeron_distinct_error_log_find_observation(
        observations, existing_num_observations, error_code, description)) == NULL)
    {
        char encoded_error[AERON_MAX_PATH];

        snprintf(encoded_error, sizeof(encoded_error) - 1, "%d: %s %s", error_code, description, message);

        size_t description_length = strlen(description);
        size_t encoded_error_length = strlen(encoded_error);
        size_t length = AERON_ERROR_LOG_HEADER_LENGTH + encoded_error_length;
        aeron_distinct_observation_t *new_array = NULL;
        char *new_description = NULL;
        size_t offset = log->next_offset;
        aeron_error_log_entry_t *entry = (aeron_error_log_entry_t *)(log->buffer + offset);

        if ((offset + length) > log->buffer_capacity ||
            aeron_alloc((void **)&new_array, sizeof(aeron_distinct_observation_t) * (num_observations + 1)) < 0 ||
            aeron_alloc((void **)&new_description, description_length + 1) < 0)
        {
            return NULL;
        }

        memcpy(log->buffer + offset + AERON_ERROR_LOG_HEADER_LENGTH, encoded_error, encoded_error_length);
        entry->first_observation_timestamp = timestamp;
        entry->observation_count = 0;

        log->next_offset = AERON_ALIGN(offset + length, AERON_ERROR_LOG_RECORD_ALIGNMENT);

        new_array[0].error_code = error_code;
        new_array[0].description = new_description;
        strncpy(new_description, description, description_length + 1);
        new_array[0].description_length = description_length;
        new_array[0].offset = offset;
        memcpy(&new_array[1], observations, sizeof(aeron_distinct_observation_t) * num_observations);

        atomic_store(&log->observations_pimpl->observations, new_array);
        atomic_store(&log->observations_pimpl->num_observations, num_observations + 1);

        AERON_PUT_ORDERED(entry->length, length);

        observation = &new_array[0];

        if (NULL != log->linger_resource)
        {
            log->linger_resource(log->linger_resource_clientd, (uint8_t *)observations);
        }
    }

    return observation;
}