bool aeron_mpsc_rb_unblock(volatile aeron_mpsc_rb_t *ring_buffer) { const size_t mask = ring_buffer->capacity - 1; int64_t head; int64_t tail; size_t consumer_index; size_t producer_index; bool unblocked = false; AERON_GET_VOLATILE(head, ring_buffer->descriptor->head_position); AERON_GET_VOLATILE(tail, ring_buffer->descriptor->tail_position); consumer_index = (int32_t)head & mask; producer_index = (int32_t)tail & mask; if (producer_index == consumer_index) { return false; } int32_t length; aeron_rb_record_descriptor_t *record = (aeron_rb_record_descriptor_t *)(ring_buffer->buffer + consumer_index); AERON_GET_VOLATILE(length, record->length); if (length < 0) { record->msg_type_id = AERON_RB_PADDING_MSG_TYPE_ID; AERON_PUT_ORDERED(record->length, -length); unblocked = true; } else if (0 == length) { const size_t limit = producer_index > consumer_index ? producer_index : ring_buffer->capacity; size_t i = consumer_index + AERON_RB_ALIGNMENT; do { record = (aeron_rb_record_descriptor_t *)(ring_buffer->buffer + i); AERON_GET_VOLATILE(length, record->length); if (0 != length) { if (scan_back_to_confirm_still_zeroed(ring_buffer->buffer, i, consumer_index)) { record = (aeron_rb_record_descriptor_t *)(ring_buffer->buffer + consumer_index); record->msg_type_id = AERON_RB_PADDING_MSG_TYPE_ID; AERON_PUT_ORDERED(record->length, i - consumer_index); unblocked = true; } break; } i += AERON_RB_ALIGNMENT; } while (i < limit); } return unblocked; }
void aeron_publication_image_on_time_event( aeron_driver_conductor_t *conductor, aeron_publication_image_t *image, int64_t now_ns, int64_t now_ms) { switch (image->conductor_fields.status) { case AERON_PUBLICATION_IMAGE_STATUS_ACTIVE: { int64_t last_packet_timestamp_ns; AERON_GET_VOLATILE(last_packet_timestamp_ns, image->last_packet_timestamp_ns); bool is_end_of_stream; AERON_GET_VOLATILE(is_end_of_stream, image->is_end_of_stream); if (0 == image->conductor_fields.subscribable.length || now_ns > (last_packet_timestamp_ns + image->conductor_fields.liveness_timeout_ns) || (is_end_of_stream && aeron_counter_get(image->rcv_pos_position.value_addr) >= aeron_counter_get_volatile(image->rcv_hwm_position.value_addr))) { image->conductor_fields.status = AERON_PUBLICATION_IMAGE_STATUS_INACTIVE; image->conductor_fields.time_of_last_status_change_ns = now_ns; aeron_driver_receiver_proxy_on_remove_publication_image( conductor->context->receiver_proxy, image->endpoint, image); } break; } case AERON_PUBLICATION_IMAGE_STATUS_INACTIVE: { if (aeron_publication_image_is_drained(image)) { image->conductor_fields.status = AERON_PUBLICATION_IMAGE_STATUS_LINGER; image->conductor_fields.time_of_last_status_change_ns = now_ns; aeron_driver_conductor_image_transition_to_linger(conductor, image); } break; } case AERON_PUBLICATION_IMAGE_STATUS_LINGER: { if (now_ns > (image->conductor_fields.time_of_last_status_change_ns + image->conductor_fields.liveness_timeout_ns)) { image->conductor_fields.status = AERON_PUBLICATION_IMAGE_STATUS_DONE; } break; } default: break; } }
int32_t aeron_counters_manager_next_counter_id(volatile aeron_counters_manager_t *manager) { int64_t now_ms = manager->clock_func(); for (int i = 0; i <= manager->free_list_index; i++) { int32_t counter_id = manager->free_list[i]; aeron_counter_metadata_descriptor_t *metadata = (aeron_counter_metadata_descriptor_t *)(manager->metadata + (counter_id * AERON_COUNTERS_MANAGER_METADATA_LENGTH)); int64_t deadline; AERON_GET_VOLATILE(deadline, metadata->free_to_reuse_deadline); if (now_ms >= deadline) { aeron_counters_manager_remove_free_list_index(manager, i); aeron_counter_value_descriptor_t *value = (aeron_counter_value_descriptor_t *)(manager->values + (counter_id * AERON_COUNTERS_MANAGER_VALUE_LENGTH)); AERON_PUT_ORDERED(value->counter_value, 0L); return counter_id; } } return ++manager->id_high_water_mark; }
bool aeron_error_log_exists(const uint8_t *buffer, size_t buffer_size) { aeron_error_log_entry_t *entry = (aeron_error_log_entry_t *)buffer; int32_t length = 0; AERON_GET_VOLATILE(length, entry->length); return (0 != length); }
bool aeron_max_flow_control_strategy_should_linger(void *state, int64_t now_ns) { aeron_max_flow_control_strategy_state_t *strategy_state = (aeron_max_flow_control_strategy_state_t *)state; bool should_linger; AERON_GET_VOLATILE(should_linger, strategy_state->should_linger); return should_linger; }
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; }
int aeron_publication_image_send_pending_loss(aeron_publication_image_t *image) { int work_count = 0; if (NULL != image->endpoint && AERON_PUBLICATION_IMAGE_STATUS_ACTIVE == image->conductor_fields.status) { int64_t change_number; AERON_GET_VOLATILE(change_number, image->end_loss_change); if (change_number != image->last_loss_change_number) { const int32_t term_id = image->loss_term_id; const int32_t term_offset = image->loss_term_offset; const int32_t length = (int32_t)image->loss_length; aeron_acquire(); if (change_number == image->begin_loss_change) { if (image->conductor_fields.is_reliable) { int send_nak_result = aeron_receive_channel_endpoint_send_nak( image->endpoint, &image->control_address, image->stream_id, image->session_id, term_id, term_offset, length); aeron_counter_ordered_increment(image->nak_messages_sent_counter, 1); work_count = send_nak_result < 0 ? send_nak_result : 1; } else { const size_t index = aeron_logbuffer_index_by_term(image->initial_term_id, term_id); uint8_t *buffer = image->mapped_raw_log.term_buffers[index].addr; if (aeron_term_gap_filler_try_fill_gap(image->log_meta_data, buffer, term_id, term_offset, length)) { aeron_counter_ordered_increment(image->loss_gap_fills_counter, 1); } work_count = 1; } image->last_loss_change_number = change_number; } } } return work_count; }
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; }
int aeron_publication_image_send_pending_status_message(aeron_publication_image_t *image) { int work_count = 0; if (NULL != image->endpoint && AERON_PUBLICATION_IMAGE_STATUS_ACTIVE == image->conductor_fields.status) { int64_t change_number; AERON_GET_VOLATILE(change_number, image->end_sm_change); if (change_number != image->last_sm_change_number) { const int64_t sm_position = image->next_sm_position; const int32_t receiver_window_length = image->next_sm_receiver_window_length; aeron_acquire(); if (change_number == image->begin_sm_change) { const int32_t term_id = aeron_logbuffer_compute_term_id_from_position( sm_position, image->position_bits_to_shift, image->initial_term_id); const int32_t term_offset = (int32_t)(sm_position & image->term_length_mask); int send_sm_result = aeron_receive_channel_endpoint_send_sm( image->endpoint, &image->control_address, image->stream_id, image->session_id, term_id, term_offset, receiver_window_length, 0); aeron_counter_ordered_increment(image->status_messages_sent_counter, 1); image->last_sm_change_number = change_number; image->last_sm_position = sm_position; image->last_sm_position_window_limit = sm_position + receiver_window_length; work_count = send_sm_result < 0 ? send_sm_result : 1; } } } return work_count; }
inline static bool scan_back_to_confirm_still_zeroed(uint8_t *buffer, size_t from, size_t limit) { size_t i = from - AERON_RB_ALIGNMENT; bool all_zeroes = true; while (i >= limit) { const aeron_rb_record_descriptor_t *record = (aeron_rb_record_descriptor_t *)(buffer + i); int32_t length; AERON_GET_VOLATILE(length, record->length); if (0 != length) { all_zeroes = false; break; } i -= AERON_RB_ALIGNMENT; } return all_zeroes; }
inline static int32_t aeron_mpsc_rb_claim_capacity(volatile aeron_mpsc_rb_t *ring_buffer, size_t required_capacity) { const size_t mask = ring_buffer->capacity - 1; int64_t head = 0; int64_t tail = 0; size_t tail_index = 0; size_t padding = 0; size_t to_buffer_end_length = 0; AERON_GET_VOLATILE(head, ring_buffer->descriptor->head_cache_position); do { int32_t available_capacity = 0; AERON_GET_VOLATILE(tail, ring_buffer->descriptor->tail_position); available_capacity = (int32_t )ring_buffer->capacity - (int32_t)(tail - head); if ((int32_t)required_capacity > available_capacity) { AERON_GET_VOLATILE(head, ring_buffer->descriptor->head_position); if (required_capacity > (ring_buffer->capacity - (int32_t)(tail - head))) { return -1; } AERON_PUT_ORDERED(ring_buffer->descriptor->head_cache_position, head); } tail_index = (int32_t)tail & mask; to_buffer_end_length = ring_buffer->capacity - tail_index; if (required_capacity > to_buffer_end_length) { size_t head_index = (int32_t)head & mask; if (required_capacity > head_index) { AERON_GET_VOLATILE(head, ring_buffer->descriptor->head_position); head_index = (int32_t)head & mask; if (required_capacity > head_index) { return -1; } AERON_PUT_ORDERED(ring_buffer->descriptor->head_cache_position, head); } padding = to_buffer_end_length; } } while (!aeron_cmpxchg64( &(ring_buffer->descriptor->tail_position), tail, tail + (int32_t)required_capacity + (int32_t)padding)); if (0 != padding) { aeron_rb_record_descriptor_t *record_header = (aeron_rb_record_descriptor_t *)(ring_buffer->buffer + tail_index); record_header->msg_type_id = AERON_RB_PADDING_MSG_TYPE_ID; AERON_PUT_ORDERED(record_header->length, padding); tail_index = 0; } return (int32_t)tail_index; }
int64_t aeron_mpsc_rb_consumer_heartbeat_time_value(volatile aeron_mpsc_rb_t *ring_buffer) { int64_t value = 0; AERON_GET_VOLATILE(value, ring_buffer->descriptor->consumer_heartbeat); return value; }