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)); }
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, ×Called, 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)); }
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, ×Called, 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)); }
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; }