[
  {
    "path": ".editorconfig",
    "content": "# noinspection EditorConfigKeyCorrectness\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = space\ninsert_final_newline = false\nmax_line_length = 120\ntab_width = 4\ntrim_trailing_whitespace = true\ncurly_bracket_next_line=true\nspaces_around_operators=true\nindent_brace_style=Allman\nij_continuation_indent_size = 8\nij_formatter_off_tag = @formatter:off\nij_formatter_on_tag = @formatter:on\nij_formatter_tags_enabled = false\nij_smart_tabs = false\nij_wrap_on_typing = false\n\n[*.css]\nij_css_align_closing_brace_with_properties = false\nij_css_blank_lines_around_nested_selector = 1\nij_css_blank_lines_between_blocks = 1\nij_css_brace_placement = end_of_line\nij_css_enforce_quotes_on_format = false\nij_css_hex_color_long_format = false\nij_css_hex_color_lower_case = false\nij_css_hex_color_short_format = false\nij_css_hex_color_upper_case = false\nij_css_keep_blank_lines_in_code = 2\nij_css_keep_indents_on_empty_lines = false\nij_css_keep_single_line_blocks = false\nij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow\nij_css_space_after_colon = true\nij_css_space_before_opening_brace = true\nij_css_use_double_quotes = true\nij_css_value_alignment = do_not_align\n\n[*.java]\nij_java_align_consecutive_assignments = false\nij_java_align_consecutive_variable_declarations = false\nij_java_align_group_field_declarations = false\nij_java_align_multiline_annotation_parameters = false\nij_java_align_multiline_array_initializer_expression = false\nij_java_align_multiline_assignment = false\nij_java_align_multiline_binary_operation = false\nij_java_align_multiline_chained_methods = false\nij_java_align_multiline_extends_list = false\nij_java_align_multiline_for = true\nij_java_align_multiline_method_parentheses = false\nij_java_align_multiline_parameters = true\nij_java_align_multiline_parameters_in_calls = false\nij_java_align_multiline_parenthesized_expression = false\nij_java_align_multiline_records = true\nij_java_align_multiline_resources = true\nij_java_align_multiline_ternary_operation = false\nij_java_align_multiline_text_blocks = false\nij_java_align_multiline_throws_list = false\nij_java_align_subsequent_simple_methods = false\nij_java_align_throws_keyword = false\nij_java_annotation_parameter_wrap = off\nij_java_array_initializer_new_line_after_left_brace = false\nij_java_array_initializer_right_brace_on_new_line = false\nij_java_array_initializer_wrap = off\nij_java_assert_statement_colon_on_next_line = false\nij_java_assert_statement_wrap = off\nij_java_assignment_wrap = off\nij_java_binary_operation_sign_on_next_line = false\nij_java_binary_operation_wrap = off\nij_java_blank_lines_after_anonymous_class_header = 0\nij_java_blank_lines_after_class_header = 0\nij_java_blank_lines_after_imports = 1\nij_java_blank_lines_after_package = 1\nij_java_blank_lines_around_class = 1\nij_java_blank_lines_around_field = 0\nij_java_blank_lines_around_field_in_interface = 0\nij_java_blank_lines_around_initializer = 1\nij_java_blank_lines_around_method = 1\nij_java_blank_lines_around_method_in_interface = 1\nij_java_blank_lines_before_class_end = 0\nij_java_blank_lines_before_imports = 1\nij_java_blank_lines_before_method_body = 0\nij_java_blank_lines_before_package = 0\nij_java_block_brace_style = next_line\nij_java_block_comment_at_first_column = true\nij_java_call_parameters_new_line_after_left_paren = false\nij_java_call_parameters_right_paren_on_new_line = false\nij_java_call_parameters_wrap = off\nij_java_case_statement_on_separate_line = true\nij_java_catch_on_new_line = true\nij_java_class_annotation_wrap = split_into_lines\nij_java_class_brace_style = next_line\nij_java_class_count_to_use_import_on_demand = 99\nij_java_class_names_in_javadoc = 1\nij_java_do_not_indent_top_level_class_members = false\nij_java_do_not_wrap_after_single_annotation = false\nij_java_do_while_brace_force = always\nij_java_doc_add_blank_line_after_description = true\nij_java_doc_add_blank_line_after_param_comments = false\nij_java_doc_add_blank_line_after_return = false\nij_java_doc_add_p_tag_on_empty_lines = true\nij_java_doc_align_exception_comments = true\nij_java_doc_align_param_comments = true\nij_java_doc_do_not_wrap_if_one_line = false\nij_java_doc_enable_formatting = true\nij_java_doc_enable_leading_asterisks = true\nij_java_doc_indent_on_continuation = false\nij_java_doc_keep_empty_lines = true\nij_java_doc_keep_empty_parameter_tag = true\nij_java_doc_keep_empty_return_tag = true\nij_java_doc_keep_empty_throws_tag = true\nij_java_doc_keep_invalid_tags = true\nij_java_doc_param_description_on_new_line = false\nij_java_doc_preserve_line_breaks = false\nij_java_doc_use_throws_not_exception_tag = true\nij_java_else_on_new_line = true\nij_java_entity_dd_suffix = EJB\nij_java_entity_eb_suffix = Bean\nij_java_entity_hi_suffix = Home\nij_java_entity_lhi_prefix = Local\nij_java_entity_lhi_suffix = Home\nij_java_entity_li_prefix = Local\nij_java_entity_pk_class = java.lang.String\nij_java_entity_vo_suffix = VO\nij_java_enum_constants_wrap = off\nij_java_extends_keyword_wrap = off\nij_java_extends_list_wrap = off\nij_java_field_annotation_wrap = split_into_lines\nij_java_finally_on_new_line = true\nij_java_for_brace_force = always\nij_java_for_statement_new_line_after_left_paren = false\nij_java_for_statement_right_paren_on_new_line = false\nij_java_for_statement_wrap = off\nij_java_generate_final_locals = true\nij_java_generate_final_parameters = true\nij_java_if_brace_force = always\nij_java_imports_layout = *,|,javax.**,java.**,|,$*\nij_java_indent_case_from_switch = true\nij_java_insert_inner_class_imports = false\nij_java_insert_override_annotation = true\nij_java_keep_blank_lines_before_right_brace = 2\nij_java_keep_blank_lines_between_package_declaration_and_header = 2\nij_java_keep_blank_lines_in_code = 2\nij_java_keep_blank_lines_in_declarations = 2\nij_java_keep_control_statement_in_one_line = true\nij_java_keep_first_column_comment = true\nij_java_keep_indents_on_empty_lines = false\nij_java_keep_line_breaks = true\nij_java_keep_multiple_expressions_in_one_line = false\nij_java_keep_simple_blocks_in_one_line = false\nij_java_keep_simple_classes_in_one_line = false\nij_java_keep_simple_lambdas_in_one_line = false\nij_java_keep_simple_methods_in_one_line = false\nij_java_label_indent_absolute = false\nij_java_label_indent_size = 0\nij_java_lambda_brace_style = next_line\nij_java_layout_static_imports_separately = true\nij_java_line_comment_add_space = false\nij_java_line_comment_at_first_column = true\nij_java_message_dd_suffix = EJB\nij_java_message_eb_suffix = Bean\nij_java_method_annotation_wrap = split_into_lines\nij_java_method_brace_style = next_line\nij_java_method_call_chain_wrap = off\nij_java_method_parameters_new_line_after_left_paren = false\nij_java_method_parameters_right_paren_on_new_line = false\nij_java_method_parameters_wrap = off\nij_java_modifier_list_wrap = false\nij_java_names_count_to_use_import_on_demand = 99\nij_java_new_line_after_lparen_in_record_header = false\nij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.*\nij_java_parameter_annotation_wrap = off\nij_java_parentheses_expression_new_line_after_left_paren = false\nij_java_parentheses_expression_right_paren_on_new_line = false\nij_java_place_assignment_sign_on_next_line = false\nij_java_prefer_longer_names = true\nij_java_prefer_parameters_wrap = false\nij_java_record_components_wrap = normal\nij_java_repeat_synchronized = true\nij_java_replace_instanceof_and_cast = false\nij_java_replace_null_check = true\nij_java_replace_sum_lambda_with_method_ref = true\nij_java_resource_list_new_line_after_left_paren = false\nij_java_resource_list_right_paren_on_new_line = false\nij_java_resource_list_wrap = off\nij_java_rparen_on_new_line_in_record_header = false\nij_java_session_dd_suffix = EJB\nij_java_session_eb_suffix = Bean\nij_java_session_hi_suffix = Home\nij_java_session_lhi_prefix = Local\nij_java_session_lhi_suffix = Home\nij_java_session_li_prefix = Local\nij_java_session_si_suffix = Service\nij_java_space_after_closing_angle_bracket_in_type_argument = false\nij_java_space_after_colon = true\nij_java_space_after_comma = true\nij_java_space_after_comma_in_type_arguments = true\nij_java_space_after_for_semicolon = true\nij_java_space_after_quest = true\nij_java_space_after_type_cast = true\nij_java_space_before_annotation_array_initializer_left_brace = false\nij_java_space_before_annotation_parameter_list = false\nij_java_space_before_array_initializer_left_brace = false\nij_java_space_before_catch_keyword = true\nij_java_space_before_catch_left_brace = true\nij_java_space_before_catch_parentheses = true\nij_java_space_before_class_left_brace = true\nij_java_space_before_colon = true\nij_java_space_before_colon_in_foreach = true\nij_java_space_before_comma = false\nij_java_space_before_do_left_brace = true\nij_java_space_before_else_keyword = true\nij_java_space_before_else_left_brace = true\nij_java_space_before_finally_keyword = true\nij_java_space_before_finally_left_brace = true\nij_java_space_before_for_left_brace = true\nij_java_space_before_for_parentheses = true\nij_java_space_before_for_semicolon = false\nij_java_space_before_if_left_brace = true\nij_java_space_before_if_parentheses = true\nij_java_space_before_method_call_parentheses = false\nij_java_space_before_method_left_brace = true\nij_java_space_before_method_parentheses = false\nij_java_space_before_opening_angle_bracket_in_type_parameter = false\nij_java_space_before_quest = true\nij_java_space_before_switch_left_brace = true\nij_java_space_before_switch_parentheses = true\nij_java_space_before_synchronized_left_brace = true\nij_java_space_before_synchronized_parentheses = true\nij_java_space_before_try_left_brace = true\nij_java_space_before_try_parentheses = true\nij_java_space_before_type_parameter_list = false\nij_java_space_before_while_keyword = true\nij_java_space_before_while_left_brace = true\nij_java_space_before_while_parentheses = true\nij_java_space_inside_one_line_enum_braces = false\nij_java_space_within_empty_array_initializer_braces = false\nij_java_space_within_empty_method_call_parentheses = false\nij_java_space_within_empty_method_parentheses = false\nij_java_spaces_around_additive_operators = true\nij_java_spaces_around_assignment_operators = true\nij_java_spaces_around_bitwise_operators = true\nij_java_spaces_around_equality_operators = true\nij_java_spaces_around_lambda_arrow = true\nij_java_spaces_around_logical_operators = true\nij_java_spaces_around_method_ref_dbl_colon = false\nij_java_spaces_around_multiplicative_operators = true\nij_java_spaces_around_relational_operators = true\nij_java_spaces_around_shift_operators = true\nij_java_spaces_around_type_bounds_in_type_parameters = true\nij_java_spaces_around_unary_operator = false\nij_java_spaces_within_angle_brackets = false\nij_java_spaces_within_annotation_parentheses = false\nij_java_spaces_within_array_initializer_braces = false\nij_java_spaces_within_braces = false\nij_java_spaces_within_brackets = false\nij_java_spaces_within_cast_parentheses = false\nij_java_spaces_within_catch_parentheses = false\nij_java_spaces_within_for_parentheses = false\nij_java_spaces_within_if_parentheses = false\nij_java_spaces_within_method_call_parentheses = false\nij_java_spaces_within_method_parentheses = false\nij_java_spaces_within_parentheses = false\nij_java_spaces_within_switch_parentheses = false\nij_java_spaces_within_synchronized_parentheses = false\nij_java_spaces_within_try_parentheses = false\nij_java_spaces_within_while_parentheses = false\nij_java_special_else_if_treatment = true\nij_java_subclass_name_suffix = Impl\nij_java_ternary_operation_signs_on_next_line = false\nij_java_ternary_operation_wrap = off\nij_java_test_name_suffix = Test\nij_java_throws_keyword_wrap = off\nij_java_throws_list_wrap = off\nij_java_use_external_annotations = false\nij_java_use_fq_class_names = false\nij_java_use_relative_indents = false\nij_java_use_single_class_imports = true\nij_java_variable_annotation_wrap = off\nij_java_visibility = public\nij_java_while_brace_force = always\nij_java_while_on_new_line = true\nij_java_wrap_comments = false\nij_java_wrap_first_method_in_call_chain = false\nij_java_wrap_long_lines = false\n\n[.editorconfig]\nij_editorconfig_align_group_field_declarations = false\nij_editorconfig_space_after_colon = false\nij_editorconfig_space_after_comma = true\nij_editorconfig_space_before_colon = false\nij_editorconfig_space_before_comma = false\nij_editorconfig_spaces_around_assignment_operators = true\n\n[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.pom,*.qrc,*.rng,*.tld,*.wadl,*.wsdd,*.wsdl,*.xjb,*.xml,*.xsd,*.xsl,*.xslt,*.xul}]\nij_xml_align_attributes = true\nij_xml_align_text = false\nij_xml_attribute_wrap = normal\nij_xml_block_comment_at_first_column = true\nij_xml_keep_blank_lines = 2\nij_xml_keep_indents_on_empty_lines = false\nij_xml_keep_line_breaks = true\nij_xml_keep_line_breaks_in_text = true\nij_xml_keep_whitespaces = false\nij_xml_keep_whitespaces_around_cdata = preserve\nij_xml_keep_whitespaces_inside_cdata = false\nij_xml_line_comment_at_first_column = true\nij_xml_space_after_tag_name = false\nij_xml_space_around_equals_in_attribute = false\nij_xml_space_inside_empty_tag = false\nij_xml_text_wrap = normal\n\n[{*.bash,*.sh,*.zsh}]\nindent_size = 2\ntab_width = 2\nij_shell_binary_ops_start_line = false\nij_shell_keep_column_alignment_padding = false\nij_shell_minify_program = false\nij_shell_redirect_followed_by_space = false\nij_shell_switch_cases_indented = false\n\n[{*.cjs,*.js}]\nij_continuation_indent_size = 4\nij_javascript_align_imports = false\nij_javascript_align_multiline_array_initializer_expression = false\nij_javascript_align_multiline_binary_operation = false\nij_javascript_align_multiline_chained_methods = false\nij_javascript_align_multiline_extends_list = false\nij_javascript_align_multiline_for = true\nij_javascript_align_multiline_parameters = true\nij_javascript_align_multiline_parameters_in_calls = false\nij_javascript_align_multiline_ternary_operation = false\nij_javascript_align_object_properties = 0\nij_javascript_align_union_types = false\nij_javascript_align_var_statements = 0\nij_javascript_array_initializer_new_line_after_left_brace = false\nij_javascript_array_initializer_right_brace_on_new_line = false\nij_javascript_array_initializer_wrap = off\nij_javascript_assignment_wrap = off\nij_javascript_binary_operation_sign_on_next_line = false\nij_javascript_binary_operation_wrap = off\nij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**\nij_javascript_blank_lines_after_imports = 1\nij_javascript_blank_lines_around_class = 1\nij_javascript_blank_lines_around_field = 0\nij_javascript_blank_lines_around_function = 1\nij_javascript_blank_lines_around_method = 1\nij_javascript_block_brace_style = end_of_line\nij_javascript_call_parameters_new_line_after_left_paren = false\nij_javascript_call_parameters_right_paren_on_new_line = false\nij_javascript_call_parameters_wrap = off\nij_javascript_catch_on_new_line = false\nij_javascript_chained_call_dot_on_new_line = true\nij_javascript_class_brace_style = end_of_line\nij_javascript_comma_on_new_line = false\nij_javascript_do_while_brace_force = never\nij_javascript_else_on_new_line = false\nij_javascript_enforce_trailing_comma = keep\nij_javascript_extends_keyword_wrap = off\nij_javascript_extends_list_wrap = off\nij_javascript_field_prefix = _\nij_javascript_file_name_style = relaxed\nij_javascript_finally_on_new_line = false\nij_javascript_for_brace_force = never\nij_javascript_for_statement_new_line_after_left_paren = false\nij_javascript_for_statement_right_paren_on_new_line = false\nij_javascript_for_statement_wrap = off\nij_javascript_force_quote_style = false\nij_javascript_force_semicolon_style = false\nij_javascript_function_expression_brace_style = end_of_line\nij_javascript_if_brace_force = never\nij_javascript_import_merge_members = global\nij_javascript_import_prefer_absolute_path = global\nij_javascript_import_sort_members = true\nij_javascript_import_sort_module_name = false\nij_javascript_import_use_node_resolution = true\nij_javascript_imports_wrap = on_every_item\nij_javascript_indent_case_from_switch = true\nij_javascript_indent_chained_calls = true\nij_javascript_indent_package_children = 0\nij_javascript_jsx_attribute_value = braces\nij_javascript_keep_blank_lines_in_code = 2\nij_javascript_keep_first_column_comment = true\nij_javascript_keep_indents_on_empty_lines = false\nij_javascript_keep_line_breaks = true\nij_javascript_keep_simple_blocks_in_one_line = false\nij_javascript_keep_simple_methods_in_one_line = false\nij_javascript_line_comment_add_space = true\nij_javascript_line_comment_at_first_column = false\nij_javascript_method_brace_style = end_of_line\nij_javascript_method_call_chain_wrap = off\nij_javascript_method_parameters_new_line_after_left_paren = false\nij_javascript_method_parameters_right_paren_on_new_line = false\nij_javascript_method_parameters_wrap = off\nij_javascript_object_literal_wrap = on_every_item\nij_javascript_parentheses_expression_new_line_after_left_paren = false\nij_javascript_parentheses_expression_right_paren_on_new_line = false\nij_javascript_place_assignment_sign_on_next_line = false\nij_javascript_prefer_as_type_cast = false\nij_javascript_prefer_explicit_types_function_expression_returns = false\nij_javascript_prefer_explicit_types_function_returns = false\nij_javascript_prefer_explicit_types_vars_fields = false\nij_javascript_prefer_parameters_wrap = false\nij_javascript_reformat_c_style_comments = false\nij_javascript_space_after_colon = true\nij_javascript_space_after_comma = true\nij_javascript_space_after_dots_in_rest_parameter = false\nij_javascript_space_after_generator_mult = true\nij_javascript_space_after_property_colon = true\nij_javascript_space_after_quest = true\nij_javascript_space_after_type_colon = true\nij_javascript_space_after_unary_not = false\nij_javascript_space_before_async_arrow_lparen = true\nij_javascript_space_before_catch_keyword = true\nij_javascript_space_before_catch_left_brace = true\nij_javascript_space_before_catch_parentheses = true\nij_javascript_space_before_class_lbrace = true\nij_javascript_space_before_class_left_brace = true\nij_javascript_space_before_colon = true\nij_javascript_space_before_comma = false\nij_javascript_space_before_do_left_brace = true\nij_javascript_space_before_else_keyword = true\nij_javascript_space_before_else_left_brace = true\nij_javascript_space_before_finally_keyword = true\nij_javascript_space_before_finally_left_brace = true\nij_javascript_space_before_for_left_brace = true\nij_javascript_space_before_for_parentheses = true\nij_javascript_space_before_for_semicolon = false\nij_javascript_space_before_function_left_parenth = true\nij_javascript_space_before_generator_mult = false\nij_javascript_space_before_if_left_brace = true\nij_javascript_space_before_if_parentheses = true\nij_javascript_space_before_method_call_parentheses = false\nij_javascript_space_before_method_left_brace = true\nij_javascript_space_before_method_parentheses = false\nij_javascript_space_before_property_colon = false\nij_javascript_space_before_quest = true\nij_javascript_space_before_switch_left_brace = true\nij_javascript_space_before_switch_parentheses = true\nij_javascript_space_before_try_left_brace = true\nij_javascript_space_before_type_colon = false\nij_javascript_space_before_unary_not = false\nij_javascript_space_before_while_keyword = true\nij_javascript_space_before_while_left_brace = true\nij_javascript_space_before_while_parentheses = true\nij_javascript_spaces_around_additive_operators = true\nij_javascript_spaces_around_arrow_function_operator = true\nij_javascript_spaces_around_assignment_operators = true\nij_javascript_spaces_around_bitwise_operators = true\nij_javascript_spaces_around_equality_operators = true\nij_javascript_spaces_around_logical_operators = true\nij_javascript_spaces_around_multiplicative_operators = true\nij_javascript_spaces_around_relational_operators = true\nij_javascript_spaces_around_shift_operators = true\nij_javascript_spaces_around_unary_operator = false\nij_javascript_spaces_within_array_initializer_brackets = false\nij_javascript_spaces_within_brackets = false\nij_javascript_spaces_within_catch_parentheses = false\nij_javascript_spaces_within_for_parentheses = false\nij_javascript_spaces_within_if_parentheses = false\nij_javascript_spaces_within_imports = false\nij_javascript_spaces_within_interpolation_expressions = false\nij_javascript_spaces_within_method_call_parentheses = false\nij_javascript_spaces_within_method_parentheses = false\nij_javascript_spaces_within_object_literal_braces = false\nij_javascript_spaces_within_object_type_braces = true\nij_javascript_spaces_within_parentheses = false\nij_javascript_spaces_within_switch_parentheses = false\nij_javascript_spaces_within_type_assertion = false\nij_javascript_spaces_within_union_types = true\nij_javascript_spaces_within_while_parentheses = false\nij_javascript_special_else_if_treatment = true\nij_javascript_ternary_operation_signs_on_next_line = false\nij_javascript_ternary_operation_wrap = off\nij_javascript_union_types_wrap = on_every_item\nij_javascript_use_chained_calls_group_indents = false\nij_javascript_use_double_quotes = true\nij_javascript_use_explicit_js_extension = global\nij_javascript_use_path_mapping = always\nij_javascript_use_public_modifier = false\nij_javascript_use_semicolon_after_statement = true\nij_javascript_var_declaration_wrap = normal\nij_javascript_while_brace_force = never\nij_javascript_while_on_new_line = false\nij_javascript_wrap_comments = false\n\n[{*.gant,*.gradle,*.groovy,*.gy}]\nij_groovy_align_group_field_declarations = false\nij_groovy_align_multiline_array_initializer_expression = false\nij_groovy_align_multiline_assignment = false\nij_groovy_align_multiline_binary_operation = false\nij_groovy_align_multiline_chained_methods = false\nij_groovy_align_multiline_extends_list = false\nij_groovy_align_multiline_for = true\nij_groovy_align_multiline_list_or_map = true\nij_groovy_align_multiline_method_parentheses = false\nij_groovy_align_multiline_parameters = true\nij_groovy_align_multiline_parameters_in_calls = false\nij_groovy_align_multiline_resources = true\nij_groovy_align_multiline_ternary_operation = false\nij_groovy_align_multiline_throws_list = false\nij_groovy_align_named_args_in_map = true\nij_groovy_align_throws_keyword = false\nij_groovy_array_initializer_new_line_after_left_brace = false\nij_groovy_array_initializer_right_brace_on_new_line = false\nij_groovy_array_initializer_wrap = off\nij_groovy_assert_statement_wrap = off\nij_groovy_assignment_wrap = off\nij_groovy_binary_operation_wrap = off\nij_groovy_blank_lines_after_class_header = 0\nij_groovy_blank_lines_after_imports = 1\nij_groovy_blank_lines_after_package = 1\nij_groovy_blank_lines_around_class = 1\nij_groovy_blank_lines_around_field = 0\nij_groovy_blank_lines_around_field_in_interface = 0\nij_groovy_blank_lines_around_method = 1\nij_groovy_blank_lines_around_method_in_interface = 1\nij_groovy_blank_lines_before_imports = 1\nij_groovy_blank_lines_before_method_body = 0\nij_groovy_blank_lines_before_package = 0\nij_groovy_block_brace_style = end_of_line\nij_groovy_block_comment_at_first_column = true\nij_groovy_call_parameters_new_line_after_left_paren = false\nij_groovy_call_parameters_right_paren_on_new_line = false\nij_groovy_call_parameters_wrap = off\nij_groovy_catch_on_new_line = false\nij_groovy_class_annotation_wrap = split_into_lines\nij_groovy_class_brace_style = end_of_line\nij_groovy_class_count_to_use_import_on_demand = 5\nij_groovy_do_while_brace_force = never\nij_groovy_else_on_new_line = false\nij_groovy_enum_constants_wrap = off\nij_groovy_extends_keyword_wrap = off\nij_groovy_extends_list_wrap = off\nij_groovy_field_annotation_wrap = split_into_lines\nij_groovy_finally_on_new_line = false\nij_groovy_for_brace_force = never\nij_groovy_for_statement_new_line_after_left_paren = false\nij_groovy_for_statement_right_paren_on_new_line = false\nij_groovy_for_statement_wrap = off\nij_groovy_if_brace_force = never\nij_groovy_import_annotation_wrap = 2\nij_groovy_imports_layout = *,|,javax.**,java.**,|,$*\nij_groovy_indent_case_from_switch = true\nij_groovy_indent_label_blocks = true\nij_groovy_insert_inner_class_imports = false\nij_groovy_keep_blank_lines_before_right_brace = 2\nij_groovy_keep_blank_lines_in_code = 2\nij_groovy_keep_blank_lines_in_declarations = 2\nij_groovy_keep_control_statement_in_one_line = true\nij_groovy_keep_first_column_comment = true\nij_groovy_keep_indents_on_empty_lines = false\nij_groovy_keep_line_breaks = true\nij_groovy_keep_multiple_expressions_in_one_line = false\nij_groovy_keep_simple_blocks_in_one_line = false\nij_groovy_keep_simple_classes_in_one_line = true\nij_groovy_keep_simple_lambdas_in_one_line = true\nij_groovy_keep_simple_methods_in_one_line = true\nij_groovy_label_indent_absolute = false\nij_groovy_label_indent_size = 0\nij_groovy_lambda_brace_style = end_of_line\nij_groovy_layout_static_imports_separately = true\nij_groovy_line_comment_add_space = false\nij_groovy_line_comment_at_first_column = true\nij_groovy_method_annotation_wrap = split_into_lines\nij_groovy_method_brace_style = end_of_line\nij_groovy_method_call_chain_wrap = off\nij_groovy_method_parameters_new_line_after_left_paren = false\nij_groovy_method_parameters_right_paren_on_new_line = false\nij_groovy_method_parameters_wrap = off\nij_groovy_modifier_list_wrap = false\nij_groovy_names_count_to_use_import_on_demand = 3\nij_groovy_parameter_annotation_wrap = off\nij_groovy_parentheses_expression_new_line_after_left_paren = false\nij_groovy_parentheses_expression_right_paren_on_new_line = false\nij_groovy_prefer_parameters_wrap = false\nij_groovy_resource_list_new_line_after_left_paren = false\nij_groovy_resource_list_right_paren_on_new_line = false\nij_groovy_resource_list_wrap = off\nij_groovy_space_after_assert_separator = true\nij_groovy_space_after_colon = true\nij_groovy_space_after_comma = true\nij_groovy_space_after_comma_in_type_arguments = true\nij_groovy_space_after_for_semicolon = true\nij_groovy_space_after_quest = true\nij_groovy_space_after_type_cast = true\nij_groovy_space_before_annotation_parameter_list = false\nij_groovy_space_before_array_initializer_left_brace = false\nij_groovy_space_before_assert_separator = false\nij_groovy_space_before_catch_keyword = true\nij_groovy_space_before_catch_left_brace = true\nij_groovy_space_before_catch_parentheses = true\nij_groovy_space_before_class_left_brace = true\nij_groovy_space_before_closure_left_brace = true\nij_groovy_space_before_colon = true\nij_groovy_space_before_comma = false\nij_groovy_space_before_do_left_brace = true\nij_groovy_space_before_else_keyword = true\nij_groovy_space_before_else_left_brace = true\nij_groovy_space_before_finally_keyword = true\nij_groovy_space_before_finally_left_brace = true\nij_groovy_space_before_for_left_brace = true\nij_groovy_space_before_for_parentheses = true\nij_groovy_space_before_for_semicolon = false\nij_groovy_space_before_if_left_brace = true\nij_groovy_space_before_if_parentheses = true\nij_groovy_space_before_method_call_parentheses = false\nij_groovy_space_before_method_left_brace = true\nij_groovy_space_before_method_parentheses = false\nij_groovy_space_before_quest = true\nij_groovy_space_before_switch_left_brace = true\nij_groovy_space_before_switch_parentheses = true\nij_groovy_space_before_synchronized_left_brace = true\nij_groovy_space_before_synchronized_parentheses = true\nij_groovy_space_before_try_left_brace = true\nij_groovy_space_before_try_parentheses = true\nij_groovy_space_before_while_keyword = true\nij_groovy_space_before_while_left_brace = true\nij_groovy_space_before_while_parentheses = true\nij_groovy_space_in_named_argument = true\nij_groovy_space_in_named_argument_before_colon = false\nij_groovy_space_within_empty_array_initializer_braces = false\nij_groovy_space_within_empty_method_call_parentheses = false\nij_groovy_spaces_around_additive_operators = true\nij_groovy_spaces_around_assignment_operators = true\nij_groovy_spaces_around_bitwise_operators = true\nij_groovy_spaces_around_equality_operators = true\nij_groovy_spaces_around_lambda_arrow = true\nij_groovy_spaces_around_logical_operators = true\nij_groovy_spaces_around_multiplicative_operators = true\nij_groovy_spaces_around_regex_operators = true\nij_groovy_spaces_around_relational_operators = true\nij_groovy_spaces_around_shift_operators = true\nij_groovy_spaces_within_annotation_parentheses = false\nij_groovy_spaces_within_array_initializer_braces = false\nij_groovy_spaces_within_braces = true\nij_groovy_spaces_within_brackets = false\nij_groovy_spaces_within_cast_parentheses = false\nij_groovy_spaces_within_catch_parentheses = false\nij_groovy_spaces_within_for_parentheses = false\nij_groovy_spaces_within_gstring_injection_braces = false\nij_groovy_spaces_within_if_parentheses = false\nij_groovy_spaces_within_list_or_map = false\nij_groovy_spaces_within_method_call_parentheses = false\nij_groovy_spaces_within_method_parentheses = false\nij_groovy_spaces_within_parentheses = false\nij_groovy_spaces_within_switch_parentheses = false\nij_groovy_spaces_within_synchronized_parentheses = false\nij_groovy_spaces_within_try_parentheses = false\nij_groovy_spaces_within_tuple_expression = false\nij_groovy_spaces_within_while_parentheses = false\nij_groovy_special_else_if_treatment = true\nij_groovy_ternary_operation_wrap = off\nij_groovy_throws_keyword_wrap = off\nij_groovy_throws_list_wrap = off\nij_groovy_use_flying_geese_braces = false\nij_groovy_use_fq_class_names = false\nij_groovy_use_fq_class_names_in_javadoc = true\nij_groovy_use_relative_indents = false\nij_groovy_use_single_class_imports = true\nij_groovy_variable_annotation_wrap = off\nij_groovy_while_brace_force = never\nij_groovy_while_on_new_line = false\nij_groovy_wrap_long_lines = false\n\n[{*.htm,*.html,*.sht,*.shtm,*.shtml}]\nij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3\nij_html_align_attributes = true\nij_html_align_text = false\nij_html_attribute_wrap = normal\nij_html_block_comment_at_first_column = true\nij_html_do_not_align_children_of_min_lines = 0\nij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p\nij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot\nij_html_enforce_quotes = false\nij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var\nij_html_keep_blank_lines = 2\nij_html_keep_indents_on_empty_lines = false\nij_html_keep_line_breaks = true\nij_html_keep_line_breaks_in_text = true\nij_html_keep_whitespaces = false\nij_html_keep_whitespaces_inside = span,pre,textarea\nij_html_line_comment_at_first_column = true\nij_html_new_line_after_last_attribute = never\nij_html_new_line_before_first_attribute = never\nij_html_quote_style = double\nij_html_remove_new_line_before_tags = br\nij_html_space_after_tag_name = false\nij_html_space_around_equality_in_attribute = false\nij_html_space_inside_empty_tag = false\nij_html_text_wrap = normal\nij_html_uniform_ident = false\n\n[{*.properties,spring.handlers,spring.schemas}]\nij_properties_align_group_field_declarations = false\nij_properties_keep_blank_lines = false\nij_properties_key_value_delimiter = equals\nij_properties_spaces_around_key_value_delimiter = false\n\n[{*.yaml,*.yml}]\nindent_size = 2\nij_yaml_keep_indents_on_empty_lines = false\nij_yaml_keep_line_breaks = true\nij_yaml_space_before_colon = true\nij_yaml_spaces_within_braces = true\nij_yaml_spaces_within_brackets = true\n"
  },
  {
    "path": ".githooks/pre-commit",
    "content": "#!/bin/sh\nset -e\n\n# stash any unstaged changes\ngit stash push -m \"prePush\" -q --keep-index\n\n# unstash the unstashed changes (if any) on exit or interrupt\nfunction unstash {\n\tgit stash apply stash^{/prePush} -q || true\n}\n\ntrap unstash EXIT\n\n./gradlew check test -q\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nA test replicating the bug will be more helpful than just a description of your issue.\nFor example, this can be a JMH test showing a performance issue or a unit test showing a logic error.\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. Linux]\n - Version [e.g. 3.4.4]\n - JVM Version [e.g. Azul Zulu 11]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n"
  },
  {
    "path": ".github/workflows/asciidoc-build-only.yml",
    "content": "name: Generate Documentation from ASCIIDoc\n\non:\n  push:\n    branches-ignore: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  checkout-and-deploy:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        java: [ 11 ]\n    steps:\n      - name: Checkout\n        uses: actions/checkout@master\n      - name: Set up java\n        uses: actions/setup-java@v2\n        with:\n          java-version: ${{ matrix.java }}\n          distribution: 'zulu'\n      - name: Build ASCIIDoc with Gradle\n        run: ./gradlew clean asciidoctor\n"
  },
  {
    "path": ".github/workflows/asciidoc.yml",
    "content": "name: Generate Github Pages from ASCIIDoc\n\non:\n  push:\n    branches: [ master ]\n\npermissions:\n  contents: write\n\njobs:\n  checkout-and-deploy:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        java: [ 11 ]\n    steps:\n      - name: Checkout\n        uses: actions/checkout@master\n      - name: Set up java\n        uses: actions/setup-java@v2\n        with:\n          java-version: ${{ matrix.java }}\n          distribution: 'zulu'\n      - name: Build ASCIIDoc with Gradle\n        run: ./gradlew clean asciidoctor\n      - name: Simple deploy with git\n        uses: JamesIves/github-pages-deploy-action@v4\n        with:\n          folder: build/docs/asciidoc/en/\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n  schedule:\n    - cron: '33 3 * * 3'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'java' ]\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v3\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v2\n      with:\n        languages: ${{ matrix.language }}\n    - name: Set up JDK 11\n      uses: actions/setup-java@v2\n      with:\n        java-version: 11\n        distribution: 'zulu'\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v2\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v2\n"
  },
  {
    "path": ".github/workflows/gradle-build.yml",
    "content": "name: Java CI with Gradle\n\non: [ push, pull_request ]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        java: [ 11, 17, 21 ]\n    name: Java ${{ matrix.java }}\n    steps:\n      - uses: actions/checkout@v2\n      - name: Set up java\n        uses: actions/setup-java@v2\n        with:\n          java-version: ${{ matrix.java }}\n          distribution: 'zulu'\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n      - name: Build with Gradle\n        run: ./gradlew build\n      - name: Archive artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: libs-and-reports-${{ matrix.java }}\n          path: |\n            build/libs\n            build/reports\n"
  },
  {
    "path": ".github/workflows/gradle-wrapper-validation.yml",
    "content": "name: \"Validate Gradle Wrapper\"\non: [push, pull_request]\n\njobs:\n  validation:\n    name: \"Validation\"\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: gradle/wrapper-validation-action@v1\n"
  },
  {
    "path": ".github/workflows/jcstress-manual.yml",
    "content": "name: JCStress Testing - manual testing\n\non:\n  workflow_dispatch:\n    inputs :\n      mode :\n        description : 'JCStress run mode: sanity, quick, default, tough, stress'\n        required : true\n        default : 'default'\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        java: [ 11, 17, 21 ]\n    name: Java ${{ matrix.java }}\n    steps:\n      - uses: actions/checkout@v2\n      - name: Set up java\n        uses: actions/setup-java@v2\n        with:\n          java-version: ${{ matrix.java }}\n          distribution: 'zulu'\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n      - name: Build with Gradle\n        run: ./gradlew jcstress -Pmode=\"${{ github.event.inputs.mode }}\"\n      - name: Archive artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: jcstress-report-manual-${{ matrix.java }}\n          path: build/reports/jcstress\n"
  },
  {
    "path": ".github/workflows/jcstress-quick.yml",
    "content": "name: JCStress Testing - commit-level quick check\n\non: [ push, pull_request ]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        java: [ 11, 17, 21 ]\n    name: Java ${{ matrix.java }}\n    steps:\n      - uses: actions/checkout@v2\n      - name: Set up java\n        uses: actions/setup-java@v2\n        with:\n          java-version: ${{ matrix.java }}\n          distribution: 'zulu'\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n      - name: Build with Gradle\n        run: ./gradlew jcstress -Pmode=quick\n      - name: Archive artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: jcstress-report-quick-${{ matrix.java }}\n          path: build/reports/jcstress\n"
  },
  {
    "path": ".gitignore",
    "content": "/bin\n/build\n/.gradle\n/out\n.DS_Store\n*~\nclasses\ncode\ntemplib\nSConstruct\n.*dblite\npom.xml\n.project\n.classpath\n.settings\n.idea\n*.iml\n*.ipr\n*.iws\n*-gc.log\ngradle.properties\nsrc/jmh/generated_tests\nsrc/jcstress/generated_tests\n"
  },
  {
    "path": ".lgtm.yml",
    "content": "extraction:\n  java:\n    index:\n      java_version: 11\n"
  },
  {
    "path": "CHANGELOG.adoc",
    "content": ":Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\ninclude::./src/docs/asciidoc/en/changelog.adoc[]"
  },
  {
    "path": "LICENCE.txt",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!) The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "README.adoc",
    "content": "= LMAX Disruptor\n\nimage:https://github.com/LMAX-Exchange/disruptor/workflows/Java%20CI%20with%20Gradle/badge.svg[Java CI with Gradle,link=https://github.com/LMAX-Exchange/disruptor/actions/workflows/gradle-build.yml]\nimage:https://github.com/LMAX-Exchange/disruptor/workflows/CodeQL/badge.svg[CodeQL,link=https://github.com/LMAX-Exchange/disruptor/actions/workflows/codeql-analysis.yml]\nimage:https://img.shields.io/github/license/LMAX-Exchange/disruptor[License,link=https://github.com/LMAX-Exchange/disruptor/blob/master/LICENCE.txt]\n\nA High Performance Inter-Thread Messaging Library\n\n== Maintainer\n\nLMAX Development Team\n\n== Support\n\n - Open a ticket in GitHub https://github.com/LMAX-Exchange/disruptor/issues[issue tracker]\n - https://groups.google.com/group/lmax-disruptor[Google Group]\n\n== Documentation\n\n* https://lmax-exchange.github.io/disruptor/[Overview]\n* https://lmax-exchange.github.io/disruptor/user-guide/index.html[User Guide]\n* https://lmax-exchange.github.io/disruptor/javadoc/com.lmax.disruptor/module-summary.html[API Documentation]\n* https://lmax-exchange.github.io/disruptor/developer-guide/index.html[Developer Guide]\n* https://github.com/LMAX-Exchange/disruptor/wiki/Frequently-Asked-Questions[FAQ]\n\n\n"
  },
  {
    "path": "build.gradle",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nplugins {\n    id 'java-library'\n    id 'maven-publish'\n    id 'signing'\n    id 'checkstyle'\n    id 'idea'\n    id \"io.github.reyerizo.gradle.jcstress\" version \"0.8.15\"\n    id 'org.asciidoctor.jvm.convert' version '3.3.2'\n    id \"me.champeau.jmh\" version \"0.6.8\"\n    id \"biz.aQute.bnd.builder\" version \"6.3.1\"\n}\n\ngroup = 'com.lmax'\nversion = new Version(major: 4, minor: 0, revision: 0, snapshot: true)\n\ndefaultTasks 'build'\n\next {\n    fullName = 'Disruptor Framework'\n    fullDescription = 'Disruptor - Concurrent Programming Framework'\n    teamName = 'LMAX Disruptor Development Team'\n    siteUrl = 'https://lmax-exchange.github.io/disruptor'\n    sourceUrl = 'git@github.com:LMAX-Exchange/disruptor.git'\n    moduleName = 'com.lmax.disruptor'\n}\n\napply from: 'gradle/maven.gradle'\napply from: 'gradle/perf.gradle'\napply from: 'gradle/jmh.gradle'\napply from: 'gradle/asciidoc.gradle'\napply from: 'gradle/jcstress.gradle'\n\nwrapper.gradleVersion = '7.6'\n\nrepositories {\n    mavenCentral()\n}\n\nsourceCompatibility = targetCompatibility = JavaVersion.VERSION_11\n\ndependencies {\n    checkstyle 'com.puppycrawl.tools:checkstyle:10.4'\n    testImplementation 'org.junit.jupiter:junit-jupiter:5.9.0'\n    testImplementation 'org.hamcrest:hamcrest:2.2'\n}\n\ncompileJava {\n    options.fork = true\n    options.debug = true\n    options.warnings = true\n    options.deprecation = true\n}\ncompileTestJava {\n    options.fork = true\n    options.debug = true\n    options.warnings = true\n    options.deprecation = true\n}\n\ntest {\n    useJUnitPlatform()\n    systemProperties = [\n            'junit.jupiter.execution.parallel.enabled': 'true',\n            'junit.jupiter.execution.parallel.mode.default': 'concurrent'\n    ]\n}\n\njavadoc {\n    title = 'Disruptor'\n\n    options.addStringOption('XDignore.symbol.file', '-quiet')\n    options.author = true\n    options.bottom = \"<i>Copyright &#169; 2011 - ${Calendar.instance[Calendar.YEAR]} LMAX Ltd. All Rights Reserved.</i>\"\n    options.use = true\n    options.version = true\n    options.showFromPublic()\n}\n\njar {\n    manifest.attributes('Built-By': System.properties.get('user.name'),\n            'Automatic-Module-Name': moduleName)\n    bnd(\n            '-exportcontents': 'com.lmax.disruptor.*;-noimport:=true',\n            '-noimportjava': 'true',\n            'Import-Package': '!*',\n            'Bundle-Name': fullName,\n            'Bundle-Vendor': teamName,\n            'Bundle-Description': fullDescription,\n            'Bundle-DocURL': siteUrl,\n            'Bundle-SymbolicName': moduleName,\n    )\n}\n\ntasks.withType(Test) {\n    maxParallelForks = (int) Math.max(Math.floor(Runtime.runtime.availableProcessors() / 2), 1)\n}\n\ntask setUpGitHooks(type: Exec, description: 'Add a pre-commit git hook that runs gradle check & test tasks') {\n    def hooksFolder = file('.githooks').getAbsolutePath()\n    commandLine 'git', 'config', 'core.hooksPath', hooksFolder\n}\n\nclass Version {\n    int major, minor = 0, revision = 0\n    boolean snapshot\n    String stage\n\n    String toString() {\n        \"$major.$minor.$revision${stage ? '.' + stage : ''}${snapshot ? '-SNAPSHOT' : ''}\"\n    }\n}\n\nsourceSets {\n    examples {\n        compileClasspath += sourceSets.main.output\n        runtimeClasspath += sourceSets.main.output\n    }\n}\n"
  },
  {
    "path": "config/checkstyle/checkstyle.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n        \"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN\"\n        \"https://checkstyle.org/dtds/configuration_1_3.dtd\">\n\n<module name=\"Checker\">\n    <module name=\"SeverityMatchFilter\">\n        <property name=\"severity\" value=\"info\"/>\n        <property name=\"acceptOnMatch\" value=\"false\"/>\n    </module>\n\n    <module name=\"FileTabCharacter\">\n        <property name=\"eachLine\" value=\"true\"/>\n    </module>\n\n    <module name=\"SuppressionFilter\">\n        <property name=\"file\" value=\"${config_loc}/suppress.xml\"/>\n    </module>\n\n    <module name=\"LineLength\">\n        <property name=\"max\" value=\"200\"/>\n        <property name=\"ignorePattern\" value=\"^[ \\t]*\\*.*@.*$\"/>\n    </module>\n\n    <module name=\"TreeWalker\">\n        <property name=\"tabWidth\" value=\"4\"/>\n        <property name=\"severity\" value=\"error\"/>\n\n        <module name=\"ConstantName\"/>\n\n        <module name=\"LocalFinalVariableName\"/>\n\n        <module name=\"LocalVariableName\"/>\n\n        <module name=\"MemberName\">\n            <property name=\"format\" value=\"^[a-z][a-zA-Z0-9_]*$\"/>\n        </module>\n\n        <module name=\"MethodName\"/>\n\n        <module name=\"PackageName\"/>\n\n        <module name=\"ParameterName\"/>\n\n        <module name=\"StaticVariableName\"/>\n\n        <module name=\"TypeName\"/>\n\n        <module name=\"AvoidStarImport\"/>\n        <module name=\"RedundantImport\"/>\n        <module name=\"UnusedImports\"/>\n\n        <module name=\"EmptyForInitializerPad\"/>\n\n        <module name=\"MethodParamPad\"/>\n\n        <module name=\"NoWhitespaceBefore\"/>\n\n        <module name=\"WhitespaceAfter\">\n            <property name=\"tokens\"\n                      value=\"COMMA, SEMI, TYPECAST, LITERAL_IF, LITERAL_ELSE,\n                    LITERAL_WHILE, LITERAL_DO, LITERAL_FOR, DO_WHILE\"/>\n        </module>\n\n        <module name=\"WhitespaceAround\">\n            <property name=\"allowEmptyConstructors\" value=\"true\"/>\n            <property name=\"allowEmptyLambdas\" value=\"true\"/>\n            <property name=\"allowEmptyMethods\" value=\"true\"/>\n            <property name=\"allowEmptyTypes\" value=\"true\"/>\n            <property name=\"allowEmptyLoops\" value=\"true\"/>\n            <property name=\"ignoreEnhancedForColon\" value=\"false\"/>\n            <property name=\"tokens\"\n                      value=\"ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR,\n                    BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, DO_WHILE, EQUAL, GE, GT, LAMBDA, LAND,\n                    LCURLY, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY,\n                    LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SWITCH, LITERAL_SYNCHRONIZED,\n                    LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN,\n                    NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR,\n                    SR_ASSIGN, STAR, STAR_ASSIGN, LITERAL_ASSERT, TYPE_EXTENSION_AND\"/>\n            <message key=\"ws.notFollowed\"\n                     value=\"WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)\"/>\n            <message key=\"ws.notPreceded\"\n                     value=\"WhitespaceAround: ''{0}'' is not preceded with whitespace.\"/>\n        </module>\n\n        <module name=\"OperatorWrap\">\n            <property name=\"tokens\" value=\"PLUS, ASSIGN\"/>\n            <property name=\"option\" value=\"eol\"/>\n        </module>\n\n        <module name=\"ParenPad\"/>\n\n        <module name=\"TypecastParenPad\"/>\n\n        <module name=\"ModifierOrder\"/>\n\n        <module name=\"RedundantModifier\"/>\n\n        <module name=\"NestedTryDepth\">\n            <property name=\"max\" value=\"2\"/>\n        </module>\n\n        <module name=\"CovariantEquals\"/>\n\n        <module name=\"NeedBraces\">\n            <property name=\"tokens\"\n                      value=\"LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF, LITERAL_WHILE\"/>\n        </module>\n\n        <module name=\"LeftCurly\">\n            <property name=\"option\" value=\"nl\"/>\n        </module>\n\n        <module name=\"RightCurly\">\n            <property name=\"option\" value=\"alone\"/>\n        </module>\n\n        <module name=\"EmptyStatement\"/>\n\n        <module name=\"EqualsHashCode\"/>\n\n        <module name=\"DefaultComesLast\"/>\n\n        <module name=\"SimplifyBooleanExpression\"/>\n\n        <module name=\"SimplifyBooleanReturn\"/>\n\n        <module name=\"StringLiteralEquality\"/>\n\n        <module name=\"PackageDeclaration\"/>\n\n        <module name=\"ReturnCount\">\n            <property name=\"max\" value=\"3\"/>\n        </module>\n\n        <module name=\"FallThrough\"/>\n\n        <module name=\"FinalClass\"/>\n\n        <module name=\"MutableException\"/>\n\n        <module name=\"ArrayTypeStyle\"/>\n\n        <module name=\"TodoComment\">\n            <property name=\"severity\" value=\"info\"/>\n            <property name=\"format\" value=\"TODO\"/>\n        </module>\n\n        <module name=\"UpperEll\"/>\n\n        <module name=\"IllegalType\">\n            <property name=\"legalAbstractClassNames\"\n                      value=\"AbstractBeanDefinition, AbstractAccountEvInstruction, AbstractEmsInstruction, AbstractEvInstruction, AbstractEmsAction, AbstractInstrumentAction, AbstractEntry\"/>\n            <property name=\"illegalClassNames\"\n                      value=\"java.util.GregorianCalendar, java.util.Hashtable, java.util.Vector\"/>\n        </module>\n\n        <module name=\"DescendantToken\">\n            <property name=\"tokens\" value=\"LITERAL_ASSERT\"/>\n            <property name=\"limitedTokens\"\n                      value=\"ASSIGN,DEC,INC,POST_DEC,POST_INC,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,DIV_ASSIGN,MOD_ASSIGN,BSR_ASSIGN,SR_ASSIGN,SL_ASSIGN,BAND_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,METHOD_CALL\"/>\n            <property name=\"maximumNumber\" value=\"2\"/>\n        </module>\n\n        <module name=\"Regexp\">\n            <property name=\"format\" value=\"[ \\t]+$\"/>\n            <property name=\"illegalPattern\" value=\"true\"/>\n            <property name=\"message\" value=\"Trailing whitespace\"/>\n        </module>\n\n        <module name=\"FinalParameters\"/>\n\n        <module name=\"JavadocParagraph\"/>\n        <module name=\"SingleLineJavadoc\"/>\n        <module name=\"JavadocMethod\">\n            <property name=\"accessModifiers\" value=\"public\"/>\n        </module>\n        <module name=\"JavadocType\">\n            <property name=\"scope\" value=\"public\"/>\n        </module>\n        <module name=\"JavadocVariable\">\n            <property name=\"scope\" value=\"public\"/>\n        </module>\n\n        <module name=\"IllegalInstantiation\"/>\n        <module name=\"MagicNumber\"/>\n        <module name=\"MissingSwitchDefault\"/>\n    </module>\n\n    <module name=\"BeforeExecutionExclusionFileFilter\">\n        <property name=\"fileNamePattern\" value=\"module\\-info\\.java$\"/>\n    </module>\n</module>"
  },
  {
    "path": "config/checkstyle/suppress.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE suppressions PUBLIC\n        \"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"\n        \"https://checkstyle.org/dtds/suppressions_1_2.dtd\">\n<suppressions>\n    <suppress checks=\"JavadocType\"\n              files=\"(examples|jcstress|perf|jmh|test)[\\\\/].*\"/>\n    <suppress checks=\"JavadocVariable\"\n              files=\"(examples|jcstress|perf|jmh|test)[\\\\/].*\"/>\n    <suppress checks=\"JavadocMethod\"\n              files=\"(examples|jcstress|perf|jmh|test)[\\\\/].*\"/>\n    <suppress checks=\"MagicNumber\"\n              files=\"(examples|jcstress|perf|jmh|test)[\\\\/].*\"/>\n    <suppress checks=\"MissingSwitchDefault\"\n              files=\"(examples|jcstress|perf|jmh|test)[\\\\/].*\"/>\n\n    <suppress checks=\"FinalParameters\"\n              files=\"(examples)[\\\\/].*\"/>\n</suppressions>\n"
  },
  {
    "path": "gradle/asciidoc.gradle",
    "content": "//\n// Configure ASCIIDoc publishing\n//\n\nasciidoctor {\n    languages 'en'\n    resources {\n        from(javadoc) {\n            into './javadoc'\n        }\n        from('src/docs/resources') {\n            into './resources'\n        }\n        from('src/docs/files') {\n            into './files'\n        }\n    }\n\n    // The attributes set here appear to _completely_ override whatever is set in\n    // the documents themselves - so to some degree it's pointless setting anything\n    // at a document level. That said, IntelliJ IDEA doesn't know this, so it's\n    // still kind of nice to have them at a document level so it doesn't complain!\n    attributes 'source-highlighter': 'rouge',\n            'toc': 'left',\n            'icons': 'font',\n            'xrefstyle': 'short',\n            'imagesdir': '.'\n    copyResourcesOnlyIf 'html5'\n    baseDirFollowsSourceFile()\n\n    asciidoctorj.version = '2.4.3'\n}"
  },
  {
    "path": "gradle/jcstress.gradle",
    "content": "//\n// Configure JCStress\n//\n\njcstress {\n    jcstressDependency 'org.openjdk.jcstress:jcstress-core:0.11'\n    includeTests = true\n    mode = project.getProperties().getOrDefault(\"mode\", \"quick\")\n}\n"
  },
  {
    "path": "gradle/jmh.gradle",
    "content": "//\n// Configure JMH benchmarks\n//\n\nsourceSets {\n    jmh {\n        compileClasspath += sourceSets.main.output + sourceSets.test.output\n        runtimeClasspath += sourceSets.main.output + sourceSets.test.output\n    }\n}\n\ndef jmhLibVersion = '1.35'\n\ndependencies {\n    jmhImplementation \"org.openjdk.jmh:jmh-core:${jmhLibVersion}\"\n    jmhAnnotationProcessor \"org.openjdk.jmh:jmh-generator-annprocess:${jmhLibVersion}\"\n\n    jmhImplementation 'net.openhft:affinity:3.23.2'\n}\n\njmh {\n    jmhVersion = jmhLibVersion\n    jvmArgsPrepend = ['-Xms256m -Xmx256m -XX:MaxDirectMemorySize=1g']\n    resultsFile.set(project.file(\"${project.buildDir}/reports/jmh/result.json\"))\n    profilers = [ 'pauses' ]\n    resultFormat = 'JSON'\n    failOnError = true\n    verbosity = 'NORMAL'\n    includeTests = true\n}\n\ntask jmhProfilers(type: JavaExec, description:'Lists the available profilers for the jmh task', group: 'jmh') {\n    classpath = sourceSets.jmh.runtimeClasspath\n    mainClass.set('org.openjdk.jmh.Main')\n    args '-lprof'\n}\n"
  },
  {
    "path": "gradle/maven.gradle",
    "content": "//\n// Configure publishing to Maven\n//\n\njava {\n    withJavadocJar()\n    withSourcesJar()\n}\n\npublishing {\n    publications {\n        disruptor(MavenPublication) {\n            from components.java\n\n            pom {\n                name = project.ext.fullName\n                description = project.ext.fullDescription\n                url = project.ext.siteUrl\n\n                scm {\n                    url = \"scm:${project.ext.sourceUrl}\"\n                    connection = \"scm:${project.ext.sourceUrl}\"\n                }\n\n                licenses {\n                    license {\n                        name = 'The Apache License, Version 2.0'\n                        url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                    }\n                }\n\n                developers {\n                    developer {\n                        id = 'team'\n                        name = teamName\n                        email = 'lmax-disruptor@googlegroups.com'\n                    }\n                }\n            }\n        }\n    }\n\n    repositories {\n        maven {\n            url project.hasProperty('sonatypeUrl') ? project['sonatypeUrl'] : 'https://oss.sonatype.org/service/local/staging/deploy/maven2'\n\n            credentials {\n                username = project.hasProperty('sonatypeUsername') ? project['sonatypeUsername'] : 'fake-user'\n                password = project.hasProperty('sonatypePassword') ? project['sonatypePassword'] : 'fake-password'\n            }\n        }\n    }\n}\n\nsigning {\n    sign publishing.publications.disruptor\n}\n"
  },
  {
    "path": "gradle/perf.gradle",
    "content": "//\n// Configure setting up performance tests\n//\n\nsourceSets {\n    perftest {\n        compileClasspath += sourceSets.main.output + sourceSets.test.output\n        runtimeClasspath += sourceSets.main.output + sourceSets.test.output\n    }\n}\n\ndependencies {\n    perftestCompileOnly 'org.hdrhistogram:HdrHistogram:2.1.12'\n}\n\nbuild.dependsOn perftestClasses\n\ntask perfJar(type: Jar, group: 'build') {\n    archiveAppendix.set('perf')\n    from sourceSets.perftest.output\n    from sourceSets.test.output\n    from { configurations.perftestCompileOnly.collect { it.isDirectory() ? it : zipTree(it) } }\n    with jar\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.10-bin.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd -P \"${APP_HOME:-./}\" > /dev/null && printf '%s\n' \"$PWD\" ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n@rem SPDX-License-Identifier: Apache-2.0\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name = 'disruptor'\n"
  },
  {
    "path": "src/docs/asciidoc/en/changelog.adoc",
    "content": ":Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\n= Changelog\n\n== 4.0.0\n\n* Minimum Java version now 11\n* Issue #323 - `WorkerPool` and `WorkProcessor` have been removed, no more `Disruptor::handleEventsWithWorkerPool`\n* `Disruptor` constructors using `Executor` have been removed. Use `ThreadFactory` instead.\n* Rolled up event handling extension interfaces on to `EventHandler`:\n** `BatchStartAware`\n** `LifecycleAware`\n** `SequenceReportingEventHandler`\n* `FatalExceptionHandler` and `IgnoreExceptionHandler` now use the JDK 9 Platform Logging API, i.e. `System.Logger`\n* Add rewind batch feature to the `BatchEventProcessor`\n* Add a maximum batch size argument to `BatchEventProcessor`\n** `EventHandler::onBatchStart` now gets both the `batchSize` as well as `queueDepth` (previously it had `batchSize` which reported queue depth)\n* Added documentation to `EventPoller`\n* `Util::log2` throws if passed a non-positive argument\n* Deprecations\n** Deprecated `ThreadHints.onSpinWait()`\n** Deprecated `Disruptor.handleExceptionsWith()` - this had been javadoc deprecated since 2015 but not in the code\n** Removed previously deprecated methods\n*** `Ringbuffer.resetTo()`\n*** `ConsumerRepository.getLastSequenceInChain()`\n\n== 3.4.3\n\n- Add Automatic-Module-Name to MANIFEST.MF\n\n== 3.4.2\n\n- Fix race condition in BatchEventProcessor with 3 or more starting/halting concurrently.\n\n== 3.4.1\n\n- Fix race between run() and halt() on BatchEventProcessor.\n\n== 3.4.0\n\n- Drop support for JDK6, support JDK7 and above only.\n- Add `ThreadHints.onSpinWait` to all busy spins within Disruptor.\n- Increase default sleep time for LockSupport.parkNanos to prevent busy spinning.\n\n== 3.3.8\n\n- Revert belt and braces WaitStrategy signalling.\n\n== 3.3.7\n\n- Add batch size to `BatchStartAware.onBatchStart()`\n- Upgrade to newer versions of gradle, checkstyle and JUnit\n- Deprecate classes & methods for later release\n- Remove JMock and rewrite tests accordingly\n\n== 3.3.6\n\n- Support adding gating sequences before calling Disruptor.start()\n- Fix minor concurrency race when dynamically adding sequences\n- Fix wrapping problem when adding work handlers to the Disruptor\n\n== 3.3.5\n\n- Fix NPE in TimeoutBlockingWaitStrategy when used with WorkProcessor\n- Add LiteTimeoutBlockingWaitStrategy\n- Resignal any waiting threads when trying to publish to a full ring buffer\n\n== 3.3.4\n\n- Small build fixes and refactorings\n- Removed unused MutableLong class\n\n== 3.3.3\n\n- Support ThreadFactory in Disruptor DSL\n- Make use of the Executor deprecated\n\n== 3.3.2\n\n- Minor Javadoc fixes, example code and file renames.\n- Additional generics for parametrised ExceptionHandler.\n\n== 3.3.1\n\n- Minor Javadoc fixes, example code and file renames.\n- Make ExceptionHandler type parametrised.\n\n== 3.3.0\n\n- Inheritance based Padding for RingBuffer and Sequencers.\n- Better DSL support for adding custom EventProcessors.\n- Remove deprecated methods (slightly breaking change)\n- Experimental LiteBlockingWaitStrategy\n- Experimental EventPoller for polling for data instead of waiting.\n\n== 3.2.1 Released (10-Mar-2014)\n\n- Minor build and IDE updates\n- Rewrite of performance tests to run without JUnit and separate Queues in to their own tests\n- Remove old throttled performance test\n- Add performance tests for immutable message example\n- Add performance tests for off-heap example\n- Remove old Caliper tests\n- Remove some stray yield() calls\n\n== 3.2.0 Released (13-Aug-2013)\n\n- Fix performance bug in WorkProcessor with MultiProducerSequencer\n- Add EventRelease support to WorkProcessor (experimental)\n- Add PingPongLatencyTest\n- Switch to HdrHistogram for latency measurement\n\n== 3.1.1 Released (9-Jul-2013)\n\n- Fix bug in WorkProcessor where consumers could get ahead of publishers\n\n== 3.1.0 Released (17-Jun-2013)\n\n- Fix bug in Disruptor DSL where some consumers wouldn't be included in the gating sequences.\n- Add support for using the EventTranslator with batch publication.\n- Support timeouts when shutting down the Disruptor using the DSL.\n\n== 3.0.1 Released (16-Apr-2013)\n\n- Remove Sequencer.ensureAvailable() and move functionality into the ProcessingSequenceBarrier.\n- Add get() method and deprecate getPublished() and getPreallocated() from the RingBuffer.\n- Add TimeoutException to SequenceBarrier.waitFor().\n- Fix off by one bug in MultiProducerSequencer.publish(lo, hi).\n- Improve testing for Sequencers.\n\n== 3.0.0 Released (10-Apr-2013)\n\n- Add remaining capacity to RingBuffer\n- Add batch publish methods to Sequencer\n- Add DataProvider interface to decouple the RingBuffer and BatchEventProcessor\n- Upgrade to gradle 1.5\n\n== 3.0.0.beta5 Released (08-Apr-2013)\n\n- Make Sequencer public\n\n== 3.0.0.beta4 Released (08-Apr-2013)\n\n- Refactoring, merge Publisher back into Sequencer and some of the gating sequence responsibilities up to the sequencer.\n\n== 3.0.0.beta3 Released (20-Feb-2013)\n\n- Significant Javadoc updates (thanks Jason Koch)\n- DSL support for WorkerPool\n- Small performance tweaks\n- Add TimeoutHandler and TimeoutBlockingWaitStrategy and support timeouts in BatchEventProcessor\n\n== 3.0.0.beta2 Released (7-Jan-2013)\n\n- Remove millisecond wakeup from BlockingWaitStrategy\n- Add RingBuffer.claimAndGetPreallocated\n- Add RingBuffer.isPublished\n\n== 3.0.0.beta1 Released (3-Jan-2013)\n\n- Remove claim strategies and replace with Publishers/Sequences, remove pluggability of claim strategies.\n- Introduce new multi-producer publisher algorithm (faster and more scalable).\n- Introduce more flexible EventPublisher interface that allow for static definition of translators\nthat can handle local values.\n- Allow for dynamic addition of gating sequences to ring buffer.  Default it to empty, will allow\nmessages to be sent and the ring buffer to wrap if there are no gating sequences defined.\n- Remove batch writes to the ring buffer.\n- Remove timeout read methods.\n- Switch to gradle build and layout the source maven style.\n- API change, remove RingBuffer.get, add RingBuffer.getPreallocated for producers and\nRingBuffer.getPublished for consumers.\n- Change maven dependency group id to com.lmax.\n- Added PhasedBackoffStrategy.\n- Remove explicit claim/forcePublish and supply a resetTo method.\n- Added better handling of cases when the gating sequence is ahead of the cursor value.\n\n== 2.10.3 Released (22-Aug-2012)\n\n- Bug fix, race condition in SequenceGroup when removing Sequences and getting current value\n\n== 2.10.2 Released (21-Aug-2012)\n\n- Bug fix, potential race condition in BlockingWaitStrategy.\n- Bug fix set initial SequenceGroup value to -1 (Issue #27).\n- Deprecate timeout methods that will be removed in version 3.\n\n== 2.10.1 (6-June-2012)\n\n- Bug fix, correct OSGI metadata.\n- Remove unnecessary code in wait strategies.\n\n== 2.10 (13-May-2012)\n\n- Remove deprecated timeout methods.\n- Added OSGI metadata to jar file.\n- Removed PaddedAtomicLong and use Sequence in all places.\n- Fix various generics warnings.\n- Change Sequence implementation to work around IBM JDK bug and improve performance by ~10%.\n- Add a remainingCapacity() call to the Sequencer class.\n\n== 2.9 (8-Apr-2012)\n\n- Deprecate timeout methods for publishing.\n- Add tryNext and tryPublishEvent for events that shouldn't block during delivery.\n- Small performance enhancement for MultithreadClaimStrategy.\n\n== 2.8 (6-Feb-2012)\n\n- Create new MultithreadClaimStrategy that works between when threads are highly contended. Previous implementation is now called MultithreadLowContentionClaimStrategy\n- Fix for bug where EventProcessors weren't being added as gating sequences to the ring buffer.\n- Fix range tracking bug in Histogram\n\n== 2.7.1  (21-Dec-2011)\n\n- Artefacts made available via maven central repository. (groupId:com.googlecode.disruptor, artifactId:disruptor) See UsingDisruptorInYourProject for details.\n\n== 2.7 (12-Nov-2011)\n\n- Changed construction API to allow user supplied claim and wait strategies\n- Added AggregateEventHandler to support multiple EventHandlers from a single BatchEventProcessor\n- Support exception handling from LifecycleAware\n- Added timeout API calls for claiming a sequence when publishing\n- Use LockSupport.parkNanos() instead of Thread.sleep() to reduce latency\n- Reworked performance tests to better support profiling and use LinkedBlockingQueue for comparison because it performs better on the latest processors\n- Minor bugfixes\n\n== 2.6\n\n- Introduced WorkerPool to allow the one time consumption of events by a worker in a pool of EventProcessors.\n- New internal implementation of SequenceGroup which is lock free at all times and garbage free for get and set operations.\n- SequenceBarrier now checks alert status on every call whether it is blocking or not.\n- Added scripts in preparation for publishing binaries to maven repository.\n\n== 2.5.1\n\n- Bugfix for supporting SequenceReportingEventHandler from DSL. ([issue 9](https://github.com/LMAX-Exchange/disruptor/issues#issue/9))\n- Bugfix for multi-threaded publishing to multiple ring buffers ([issue 10](https://github.com/LMAX-Exchange/disruptor/issues#issue/10))\n- Change SequenceBarrier to always check alert status before entering waitFor cycle.  Previously this was only checked when the requested sequence was not available.\n- Change ClaimStrategy to not spin when the buffer has no available capacity, instead go straight to yielding to allow event processors to catch up.\n\n== 2.5\n\n- Changed RingBuffer and publisher API so any mutable object can be placed in the RingBuffer without having to extend AbstractEvent\n- Added EventPublisher implementation to allow the publishing steps to be combined into one action\n- DisruptorWizard has been renamed to Disruptor with added support for any subtype of EventProcessor\n- Introduced a new Sequencer class that allows the Disruptor to be applied to other data structures such as multiple arrays.  This can be a very useful pattern when multiple event processors work on the same event and you want to avoid false sharing.  The Diamond for FizzBuzz is a good example of the issue.  It is also higher performance by avoiding the pointer indirection when arrays of primitives are used.\n- Further increased performance and scalability by reducing false sharing.\n- Added progressive backoff strategy to the MultiThreadedClaimStrategy to prevent publisher getting into the claim cycle when the buffer is full because of a slow EventProcessor.\n- Significantly improved performance to WaitStrategy.Option.BLOCKING\n- Introduced SequenceGroup to allow dynamic registration of EventProcessors.\n\n== 2.0.2\n\n- Rework of \"False Sharing\" prevention which makes the performance much more predictable across all platforms. Special thanks to Jeff Hain for helping focus in on a solution.\n\n== 2.0.1\n\n- Renaming mistake for publishEventAtSequence should have been claimEventAtSequence\n- Fixed bug in YieldingStrategy that was busy spinning more than yielding and introduced SleepingStrategy\n- Removed code duplication in Unicast perf tests for expected result\n\n== 2.0.0\n\n- New API to reflect naming changes\n- Producer -> Publisher\n- Entry -> Event\n- Consumer -> EventProcessor\n- ConsumerBarrier -> DependencyBarrier\n- ProducerBarrier has been incorporated into the RingBuffer for ease of use\n- DisruptorWizard integrated for fluent API dependency graph construction\n- Rework of sequence tracking to avoid false sharing on Java 7, plus avoid mega-morphic calls to make better use of the instruction cache\n- Reduced usage of memory barriers where possible\n- WaitStrategy.YIELDING initially spins for a short period to reduce latency\n- Major performance improvement giving more than a 2X increase for throughput across most use cases.\n\n== 1.2.2\n\n- ProducerBarrier change to yield after busy spinning for a while.  This may help the situation when the the number of producers exceeds the number of cores.\n\n== 1.2.1\n\n- Bug fix for setting the sequence in the ForceFillProducerBarrier.\n- Code syntax tidy up.\n\n== 1.2.0\n\n- Bug fix for regression introduced inlining multi-thread producer commit tracking code.  This was a critical bug for the multi-threaded producer scenario.\n- Added new ProducerBarrier method for claiming a batch of sequences.  This feature can give a significant throughput increase.\n\n== 1.1.0\n\n- Off by one regression bug in ProducerBarrier introduced in 1.0.9.\n- Clarified the algorithm for initial cursor value in the ClaimStrategy.\n\n== 1.0.9\n\n- Added Apache 2.0 licence and comments.\n- Small performance improvements to producers barriers and BatchConsumer.\n\n== 1.0.8\n\n- Bugfix for BatchConsumer sequence update when using SequenceTrackingHandler to ensure sequence is always updated at the end of a batch regardless.\n\n== 1.0.7\n\n- Factored out LifecycleAware interface to allowing consumers handlers to be notified when their thread starts and shuts down.\n\n== 1.0.6\n\n- Cache minimum consumer sequence in producer barriers.  This helps make the performance more predictable on Nehalem processors and greater on earlier Core 2 processors.\n\n== 1.0.5\n\n- Removed Entry interface.  All Entries must now extend AbstractEntry.\n- Made setSequence package private on AbstractEntry for encapsulation.\n"
  },
  {
    "path": "src/docs/asciidoc/en/developer-guide/10_getting_and_building.adoc",
    "content": "= Getting & Building the Disruptor\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\nA guide to checking out the code and building it\n\n== Getting Started\n\n1. Check out the project locally to your machine\n+\n--\n[source,shell script]\n----\n$ git clone git://github.com/LMAX-Exchange/disruptor.git\n$ cd disruptor\n----\n--\n\n2. Build a distribution\n+\n--\n[source,shell script]\n----\n$ ./gradlew clean build\n----\nAs a result of the build you should find the following files:\n\n- `disruptor/build/libs/disruptor-{VERSION_NUMBER}-SNAPSHOT.jar`\n- `disruptor/build/libs/disruptor-{VERSION_NUMBER}-SNAPSHOT-javadoc.jar`\n- `disruptor/build/libs/disruptor-{VERSION_NUMBER}-SNAPSHOT-sources.jar`\n--\n\n3. Run the tests\n+\n--\n[source,shell script]\n----\n$ ./gradlew test\n----\n--"
  },
  {
    "path": "src/docs/asciidoc/en/developer-guide/20_performance_tests.adoc",
    "content": "= Disruptor Performance Tests\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\n== Run the performance tests\n\nWhen making changes to the Disruptor it is important to be aware of the performance impact of your change.\n\nTo measure the performance characteristics of the Disruptor there are many tests in the `perftest` and `jmh` sourcesets.\n\n=== Running Perf Tests\n\nThe perf tests are all under `src/perftest` and are built using a custom framework.\n\nTo run them you need to fist build the perf jar and then run a single test at a time, for example:\n\n[source,shell script]\n----\n$ ./gradlew perfJar\n$ java -cp build/libs/disruptor-perf-*.jar com.lmax.disruptor.sequenced.OneToOneSequencedThroughputTest\n----\n\n=== Running JMH Tests\n\nThere are also https://github.com/openjdk/jmh/[JMH Benchmarks] for testing the performance of the Disruptor, these can be run with a gradle command\n\n[source,shell script]\n----\n$ ./gradlew jmh\n----\n\n==== Isolated CPU benchmarking\n\nSome JMH Benchmarks can be run on machines with isolated cpus to get results with less error.\n\nBuild the `jmhJar` on your development machine and transfer it to your benchmarking machine with isolated cpus:\n\n[source,shell script]\n----\ndev-machine /path/to/disruptor $ ./gradlew jmhJar\ndev-machine /path/to/disruptor $ scp dev-machine:build/lib/disruptor-*-jmh.jar bench-machine:\n----\n\nAssuming a system set up with isolated cores, e.g.\n\n[source,shell script]\n----\nbench-machine ~ $ cat /proc/cmdline\n... isolcpus=31,33,35,37,39,41,43,45,47,7,9,11,13,15,17,19,21,23 nohz_full=31,33,35,37,39,41,43,45,47,7,9,11,13,15,17,19,21,23 ...\n----\n\nAnd the system may have a `cpuset` setup to split application threads from sharing cpus with kernel code:\n\n[source,shell script]\n----\nbench-machine ~ $ cat /cpusets/app/cpus\n5,7-23,29,31-47\n----\n\nYou can run the benchmarks taskset to some of those cpus so that Java threads (like GC and complication) run on some cores\nand JMH Benchmark threads are pinned to isolated cpus using the following command (which is running just the one benchmark, `MultiProducersSequencerBenchmark`):\n\n[source,shell script]\n----\nbench-machine ~ $ cat runBenchmarks.sh\n#!/bin/bash\nJAVA_HOME=/opt/jdk11/1.11.0.6_zulu11.37.17_ca-1\nISOLATED_CPUS=7,9,11,13,15,17,19,21,23 $JAVA_HOME/bin/java -jar ./disruptor-4.0.0-SNAPSHOT-jmh.jar -rf json -rff /tmp/jmh-result.json -foe true -v NORMAL -prof perf -jvmArgsPrepend -Xmx256m -jvmArgsPrepend -Xms256m -jvmArgsPrepend -XX:MaxDirectMemorySize=1g $@\n\nbench-machine ~ $ sudo cset proc -v --exec app -- taskset -c 5,8,10,12,14,16,18,20,22,29,32,34,36,38,40,42,44,46 ./runBenchmarks.sh MultiProducersSequencerBenchmark\n----\n"
  },
  {
    "path": "src/docs/asciidoc/en/developer-guide/25_jsctress_tests.adoc",
    "content": "= jcstress Tests\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\nhttps://github.com/openjdk/jcstress/\n\n> The Java Concurrency Stress (jcstress) is the experimental harness and a suite of tests to aid the research in the correctness of concurrency support in the JVM, class libraries, and hardware.\n\nThe Disruptor has some jcstress tests to experiment and validate the correctness of the concurrency promises that the\nDisruptor makes.\n\n== Running jcstress Tests\n\n[source,shell script]\n----\n$ ./gradlew jcstress\n----\n"
  },
  {
    "path": "src/docs/asciidoc/en/developer-guide/30_publishing_release.adoc",
    "content": "= Publishing Release\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\n== Prerequisites\n\n1. All tests should be completing successfully in CI and locally\n2. The changelog is updated with relevant information\n3. `build.gradle` has been updated with the version information for the proposed release, and pushed to GitHub\n4. Create a new release via GitHub UI, this should tag the commit\n\n== GPG Key\n\nTo sign the artifact, a requirement for public release, you must have a signing GPG key set up.\n\n=== Creating a new GPG signing key\n\nIf you already have a GPG signing key, you can skip to the next section.\n\n- If you are on version 2.1.17 or greater, run the command below to generate a GPG key pair:\n+\n--\n[source,shell script]\n----\n$ gpg --full-generate-key\n----\n  - At the prompt, specify the kind of key you want, or press Enter to accept the default `RSA and RSA`.\n  - Enter the desired key size. Your key must be at least 4096 bits.\n  - Enter the length of time the key should be valid. Press Enter to specify the default selection, indicating that the key doesn't expire.\n--\n\n - If you are not on version 2.1.17 or greater, the `gpg --full-generate-key` command doesn't work. Use the following command instead:\n+\n--\n[source,shell script]\n----\n$ gpg --default-new-key-algo rsa4096 --gen-key\n----\n--\n\n - Verify that your selections are correct.\n - Enter your user ID information.\n - Type a secure passphrase.\n - (is using gpg >= 2.1) Export the keyring to a gpg file\n+\n--\n[source,shell script]\n----\ngpg --keyring secring.gpg --export-secret-keys > ~/.gnupg/secring.gpg\n----\n--\n\n=== Adding signing options for gradle\n\n - `signing.keyId` is the last 8 characters of the public key id for the signing key, in this example, `2657EDD1`.\n - `signing.password` is the passphrase for your keyring\n - `signing.secretKeyRingFile` is the absolute path to the secret key ring file containing your private key\n\n[source,shell script]\n----\n$ gpg --list-secret-keys --keyid-format SHORT\n/home/dev/.gnupg/pubring.kbx\n-----------------------------\nsec   rsa4096/2657EDD1 2021-12-31 [SC]\n      EA38CE5CFD74BBB831611491F9CE691A2657EDD1\nuid         [ultimate] LMAX Coders (LMAX Dev Team) <coders@lmax.com>\nssb   rsa4096/F4831415 2021-12-31 [E]\n\n\n$ cat gradle.properties\nsigning.keyId=2657EDD1\nsigning.password=<passphrase used to protect your private key>\nsigning.secretKeyRingFile=/home/dev/.gnupg/secring.gpg\n----\n\nSee: https://docs.gradle.org/current/userguide/signing_plugin.html\n\n=== Publish your public key\n\nYou need to publish your public key so that sonatype can verify who signed the release artifacts.\n\n----\ngpg --keyserver https://keyserver.ubuntu.com/ --send-keys 2657EDD1\n----\n\nNote: Other `keyservers` are available\n\n== Release process\n\n1. Clean any existing build data\n+\n--\n[source,shell script]\n----\n$ ./gradlew clean\n----\n--\n2. Add `gradle.properties` file in the root of the disruptor project with the following content\n+\n--\n[source,shell script]\n----\n$ cat gradle.properties\n\nsonatypeUsername=<username for sonatype>\nsonatypePassword=<password for sonatype>\nsigning.keyId=<signing-key>\nsigning.password=<password>>\nsigning.secretKeyRingFile=/home/dev/.gnupg/secring.gpg\n----\n--\n3. Build & upload to Sonatype\n+\n--\n[source,shell script]\n----\n$ ./gradlew publish\n----\n*Note: Make sure the signing step was not skipped*\n--\n4. Release in to Sonatype\n+\n--\n - Log in to https://oss.sonatype.org/\n - Go to https://oss.sonatype.org/#stagingRepositories[Staging Repositories]\n - Verify all the files are present and correct (including `*.asc` files generated by signing)\n - Close the staging repository\n - Release the repository\n - Assuming all went well, wait to see changes at: https://repo1.maven.org/maven2/com/lmax/disruptor/\n--\n5. Remove `gradle.properties` file\n+\n--\nThis file is ignored from git, but I would not advise leaving it on disk long term as it has 2 passwords in plain text.\n--"
  },
  {
    "path": "src/docs/asciidoc/en/developer-guide/90_tips.adoc",
    "content": "= Development tips\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\n== Git Hooks\n\nThis project uses GitHub Actions for CI which runs the gradle build task to check the project can be built on each\ncommit/pull request.\n\nSo that you don't push changes that will fail the simple `test` & `check` steps we would suggest adding the git pre-commit\nhook which will block any commit you try to do locally if the code fails these steps.\n\nThe git hook can be set up using the following gradle task:\n\n[source,shell script]\n----\n$ ./gradlew setUpGitHooks\n----\n\n== Signed Commits\n\n> Git is cryptographically secure, but it’s not foolproof. If you’re taking work from others on the internet and want to verify that commits are actually from a trusted source, Git has a few ways to sign and verify work using GPG.\n\n - https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work\n - https://docs.github.com/en/github/authenticating-to-github/signing-commits\n"
  },
  {
    "path": "src/docs/asciidoc/en/developer-guide/index.adoc",
    "content": "= LMAX Disruptor Developer Guide\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n:xrefstyle: short\n\nLMAX welcomes outside contributions to the Disruptor. The following documentation should help you get checked out,\nset up, and ready to start making changes to the codebase.\n\n// Leave some gaps between these includes (trust me)\n\ninclude::10_getting_and_building.adoc[leveloffset=+1]\n\ninclude::20_performance_tests.adoc[leveloffset=+1]\ninclude::25_jsctress_tests.adoc[leveloffset=+1]\n\ninclude::30_publishing_release.adoc[leveloffset=+1]\n\ninclude::90_tips.adoc[leveloffset=+1]\n"
  },
  {
    "path": "src/docs/asciidoc/en/disruptor.adoc",
    "content": "= LMAX Disruptor: High performance alternative to bounded queues for exchanging data between concurrent threads\nMartin Thompson; Dave Farley; Michael Barker; Patricia Gee; Andrew Stewart\nv1.0, May 2011\n\n:sectnums:\n:toc: left\n:authors: Martin Thompson, Dave Farley, Michael Barker, Patricia Gee, Andrew Stewart\n:email:\n:date: 2011-05\n:revnumber: 1.0\n\n// If you're changing these, also check out asciidoctor.gradle!\n:xrefstyle: short\n:icons: font\n:gradle-rootdir: ../../../../\n:imagesdir: ../../\n\nhttps://github.com/LMAX-Exchange/disruptor\n\n.Abstract\n[Abstract]\n****\nLMAX was established to create a very high performance financial exchange.\nAs part of our work to accomplish this goal we have evaluated several approaches to the design of such a system, but as we began to measure these we ran into some fundamental limits with conventional approaches.\n\nMany applications depend on queues to exchange data between processing stages.\nOur performance testing showed that the latency costs, when using queues in this way, were in the same order of magnitude as the cost of IO operations to disk (RAID or SSD based disk system) – dramatically slow.\nIf there are multiple queues in an end-to-end operation, this will add hundreds of microseconds to the overall latency.\nThere is clearly room for optimisation.\n\nFurther investigation and a focus on the computer science made us realise that the conflation of concerns inherent in conventional approaches, (e.g. queues and processing nodes) leads to contention in multi-threaded implementations, suggesting that there may be a better approach.\n\nThinking about how modern CPUs work, something we like to call \"`mechanical sympathy`\", using good design practices with a strong focus on teasing apart the concerns, we came up with a data structure and a pattern of use that we have called the Disruptor.\n\nTesting has shown that the mean latency using the Disruptor for a three-stage pipeline is 3 orders of magnitude lower than an equivalent queue-based approach.\nIn addition, the Disruptor handles approximately 8 times more throughput for the same configuration.\n\nThese performance improvements represent a step change in the thinking around concurrent programming.\nThis new pattern is an ideal foundation for any asynchronous event processing architecture where high-throughput and low-latency is required.\n\nAt LMAX we have built an order matching engine, real-time risk management, and a highly available in-memory transaction processing system all on this pattern to great success.\nEach of these systems has set new performance standards that, as far as we can tell, are unsurpassed.\n\nHowever this is not a specialist solution that is only of relevance in the Finance industry.\nThe Disruptor is a general-purpose mechanism that solves a complex problem in concurrent programming in a way that maximizes performance, and that is simple to implement.\nAlthough some of the concepts may seem unusual it has been our experience that systems built to this pattern are significantly simpler to implement than comparable mechanisms.\n\nThe Disruptor has significantly less write contention, a lower concurrency overhead and is more cache friendly than comparable approaches, all of which results in greater throughput with less jitter at lower latency.\nOn processors at moderate clock rates we have seen over 25 million messages per second and latencies lower than 50 nanoseconds.\nThis performance is a significant improvement compared to any other implementation that we have seen.\nThis is very close to the theoretical limit of a modern processor to exchange data between cores.\n****\n\n== Overview\nThe Disruptor is the result of our efforts to build the world’s highest performance financial exchange at LMAX.\nEarly designs focused on architectures derived from SEDA footnote:SEDA[Staged Event-Driven Architecture – https://en.wikipedia.org/wiki/Staged_event-driven_architecture] and Actors footnote:actors[Actor model – http://dspace.mit.edu/handle/1721.1/6952] using pipelines for throughput.\nAfter profiling various implementations it became evident that the queuing of events between stages in the pipeline was dominating the costs.\nWe found that queues also introduced latency and high levels of jitter.\nWe expended significant effort on developing new queue implementations with better performance.\nHowever it became evident that queues as a fundamental data structure are limited due to the conflation of design concerns for the producers, consumers, and their data storage.\nThe Disruptor is the result of our work to build a concurrent structure that cleanly separates these concerns.\n\n== The Complexities of Concurrency\nIn the context of this document, and computer science in general, concurrency means not only that two or more tasks happen in parallel, but also that they contend on access to resources.\nThe contended resource may be a database, file, socket or even a location in memory.\n\nConcurrent execution of code is about two things, mutual exclusion and visibility of change.\nMutual exclusion is about managing contended updates to some resource.\nVisibility of change is about controlling when such changes are made visible to other threads.\nIt is possible to avoid the need for mutual exclusion if you can eliminate the need for contended updates.\nIf your algorithm can guarantee that any given resource is modified by only one thread, then mutual exclusion is unnecessary.\nRead and write operations require that all changes are made visible to other threads.\nHowever only contended write operations require the mutual exclusion of the changes.\n\nThe most costly operation in any concurrent environment is a contended write access.\nTo have multiple threads write to the same resource requires complex and expensive coordination.\nTypically this is achieved by employing a locking strategy of some kind.\n\n=== The Cost of Locks\nLocks provide mutual exclusion and ensure that the visibility of change occurs in an ordered manner.\nLocks are incredibly expensive because they require arbitration when contended.\nThis arbitration is achieved by a context switch to the operating system kernel which will suspend threads waiting on a lock until it is released.\nDuring such a context switch, as well as releasing control to the operating system which may decide to do other house-keeping tasks while it has control, execution context can lose previously cached data and instructions.\nThis can have a serious performance impact on modern processors.\nFast user mode locks can be employed but these are only of any real benefit when not contended.\n\nWe will illustrate the cost of locks with a simple demonstration.\nThe focus of this experiment is to call a function which increments a 64-bit counter in a loop 500 million times.\nThis can be executed by a single thread on a 2.4Ghz Intel Westmere EP in just 300ms if written in Java.\nThe language is unimportant to this experiment and results will be similar across all languages with the same basic primitives.\n\nOnce a lock is introduced to provide mutual exclusion, even when the lock is as yet un-contended, the cost goes up significantly.\nThe cost increases again, by orders of magnitude, when two or more threads begin to contend.\nThe results of this simple experiment are shown in the table below:\n\n.Comparative costs of contention\n[cols2*,options=\"header\"]\n|===\n| Method | Time (ms)\n\n| Single thread\n| 300\n\n| Single thread with lock\n| 10,000\n\n| Two threads with lock\n| 224,000\n\n| Single thread with CAS\n| 5,700\n\n| Two threads with CAS\n| 30,000\n\n| Single thread with volatile write\n| 4,700\n|===\n\n=== The Costs of \"`CAS`\"\nA more efficient alternative to the use of locks can be employed for updating memory when the target of the update is a single word.\nThese alternatives are based upon the atomic, or interlocked, instructions implemented in modern processors.\nThese are commonly known as CAS (Compare And Swap) operations, e.g. \"`lock cmpxchg`\" on x86.\nA CAS operation is a special machine-code instruction that allows a word in memory to be conditionally set as an atomic operation.\nFor the \"`increment a counter experiment`\" each thread can spin in a loop reading the counter then try to atomically set it to its new incremented value.\nThe old and new values are provided as parameters to this instruction.\nIf, when the operation is executed, the value of the counter matches the supplied expected value, the counter is updated with the new value.\nIf, on the other hand, the value is not as expected, the CAS operation will fail.\nIt is then up to the thread attempting to perform the change to retry, re-reading the counter incrementing from that value and so on until the change succeeds.\nThis CAS approach is significantly more efficient than locks because it does not require a context switch to the kernel for arbitration.\nHowever CAS operations are not free of cost.\nThe processor must lock its instruction pipeline to ensure atomicity and employ a memory barrier to make the changes visible to other threads.\nCAS operations are available in Java by using the `java.util.concurrent.Atomic*` classes.\n\nIf the critical section of the program is more complex than a simple increment of a counter it may take a complex state machine using multiple CAS operations to orchestrate the contention.\nDeveloping concurrent programs using locks is difficult; developing lock-free algorithms using CAS operations and memory barriers is many times more complex and it is very difficult to prove that they are correct.\n\nThe ideal algorithm would be one with only a single thread owning all writes to a single resource with other threads reading the results.\nTo read the results in a multi-processor environment requires memory barriers to make the changes visible to threads running on other processors.\n\n=== Memory Barriers\nModern processors perform out-of-order execution of instructions and out-of-order loads and stores of data between memory and execution units for performance reasons.\nThe processors need only guarantee that program logic produces the same results regardless of execution order.\nThis is not an issue for single-threaded programs.\nHowever, when threads share state it is important that all memory changes appear in order, at the point required, for the data exchange to be successful.\nMemory barriers are used by processors to indicate sections of code where the ordering of memory updates is important.\nThey are the means by which hardware ordering and visibility of change is achieved between threads.\nCompilers can put in place complimentary software barriers to ensure the ordering of compiled code, such software memory barriers are in addition to the hardware barriers used by the processors themselves.\n\nModern CPUs are now much faster than the current generation of memory systems.\nTo bridge this divide CPUs use complex cache systems which are effectively fast hardware hash tables without chaining.\nThese caches are kept coherent with other processor cache systems via message passing protocols.\nIn addition, processors have \"`store buffers`\" to offload writes to these caches, and \"`invalidate queues`\" so that the cache coherency protocols can acknowledge invalidation messages quickly for efficiency when a write is about to happen.\n\nWhat this means for data is that the latest version of any value could, at any stage after being written, be in a register, a store buffer, one of many layers of cache, or in main memory.\nIf threads are to share this value, it needs to be made visible in an ordered fashion and this is achieved through the coordinated exchange of cache coherency messages.\nThe timely generation of these messages can be controlled by memory barriers.\n\nA read memory barrier orders load instructions on the CPU that executes it by marking a point in the invalidate queue for changes coming into its cache.\nThis gives it a consistent view of the world for write operations ordered before the read barrier.\n\nA write barrier orders store instructions on the CPU that executes it by marking a point in the store buffer, thus flushing writes out via its cache.\nThis barrier gives an ordered view to the world of what store operations happen before the write barrier.\n\nA full memory barrier orders both loads and stores but only on the CPU that executes it.\n\nSome CPUs have more variants in addition to these three primitives but these three are sufficient to understand the complexities of what is involved.\nIn the Java memory model the read and write of a volatile field implements the read and write barriers respectively.\nThis was made explicit in the Java Memory Model footnote:jmm[Java Memory Model - https://jcp.org/en/jsr/detail?id=133] as defined with the release of Java 5.\n\n=== Cache Lines\nThe way in which caching is used in modern processors is of immense importance to successful high performance operation.\nSuch processors are enormously efficient at churning through data and instructions held in cache and yet, comparatively, are massively inefficient when a cache miss occurs.\n\nOur hardware does not move memory around in bytes or words.\nFor efficiency, caches are organised into cache-lines that are typically 32-256 bytes in size, the most common cache-line being 64 bytes.\nThis is the level of granularity at which cache coherency protocols operate.\nThis means that if two variables are in the same cache line, and they are written to by different threads, then they present the same problems of write contention as if they were a single variable.\nThis is a concept know as \"`false sharing`\".\nFor high performance then, it is important to ensure that independent, but concurrently written, variables do not share the same cache-line if contention is to be minimised.\n\nWhen accessing memory in a predictable manner CPUs are able to hide the latency cost of accessing main memory by predicting which memory is likely to be accessed next and pre-fetching it into the cache in the background.\nThis only works if the processors can detect a pattern of access such as walking memory with a predictable \"`stride`\".\nWhen iterating over the contents of an array the stride is predictable and so memory will be pre-fetched in cache lines, maximizing the efficiency of the access.\nStrides typically have to be less than 2048 bytes in either direction to be noticed by the processor.\nHowever, data structures like linked lists and trees tend to have nodes that are more widely distributed in memory with no predictable stride of access.\nThe lack of a consistent pattern in memory constrains the ability of the system to pre-fetch cache-lines, resulting in main memory accesses which can be more than 2 orders of magnitude less efficient.\n\n=== The Problems of Queues\nQueues typically use either linked-lists or arrays for the underlying storage of elements.\nIf an in-memory queue is allowed to be unbounded then for many classes of problem it can grow unchecked until it reaches the point of catastrophic failure by exhausting memory.\nThis happens when producers outpace the consumers.\nUnbounded queues can be useful in systems where the producers are guaranteed not to outpace the consumers and memory is a precious resource, but there is always a risk if this assumption doesn’t hold and queue grows without limit.\nTo avoid this catastrophic outcome, queues are commonly constrained in size (bounded).\nKeeping a queue bounded requires that it is either array-backed or that the size is actively tracked.\n\nQueue implementations tend to have write contention on the head, tail, and size variables.\nWhen in use, queues are typically always close to full or close to empty due to the differences in pace between consumers and producers.\nThey very rarely operate in a balanced middle ground where the rate of production and consumption is evenly matched.\nThis propensity to be always full or always empty results in high levels of contention and/or expensive cache coherence.\nThe problem is that even when the head and tail mechanisms are separated using different concurrent objects such as locks or CAS variables, they generally occupy the same cache-line.\n\nThe concerns of managing producers claiming the head of a queue, consumers claiming the tail, and the storage of nodes in between make the designs of concurrent implementations very complex to manage beyond using a single large-grain lock on the queue.\nLarge grain locks on the whole queue for put and take operations are simple to implement but represent a significant bottleneck to throughput.\nIf the concurrent concerns are teased apart within the semantics of a queue then the implementations become very complex for anything other than a single producer – single consumer implementation.\n\nIn Java there is a further problem with the use of queues, as they are significant sources of garbage.\nFirstly, objects have to be allocated and placed in the queue.\nSecondly, if linked-list backed, objects have to be allocated representing the nodes of the list.\nWhen no longer referenced, all these objects allocated to support the queue implementation need to be re-claimed.\n\n=== Pipelines and Graphs\nFor many classes of problem it makes sense to wire together several processing stages into pipelines. Such pipelines often have parallel paths, being organised into graph-like topologies.\nThe links between each stage are often implemented by queues with each stage having its own thread.\n\nThis approach is not cheap - at each stage we have to incur the cost of en-queuing and de-queuing units of work.\nThe number of targets multiplies this cost when the path must fork, and incurs an inevitable cost of contention when it must re-join after such a fork.\n\nIt would be ideal if the graph of dependencies could be expressed without incurring the cost of putting the queues between stages.\n\n== Design of the LMAX Disruptor\nWhile trying to address the problems described above, a design emerged through a rigorous separation of the concerns that we saw as being conflated in queues.\nThis approach was combined with a focus on ensuring that any data should be owned by only one thread for write access, therefore eliminating write contention.\nThat design became known as the \"`Disruptor`\".\nIt was so named because it had elements of similarity for dealing with graphs of dependencies to the concept of \"`Phasers`\" footnote:phasers[Phasers - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/Phaser.html] in Java 7, introduced to support Fork-Join.\n\nThe LMAX disruptor is designed to address all of the issues outlined above in an attempt to maximize the efficiency of memory allocation, and operate in a cache-friendly manner so that it will perform optimally on modern hardware.\n\nAt the heart of the disruptor mechanism sits a pre-allocated bounded data structure in the form of a ring-buffer.\nData is added to the ring buffer through one or more producers and processed by one or more consumers.\n\n=== Memory Allocation\nAll memory for the ring buffer is pre-allocated on start up.\nA ring-buffer can store either an array of pointers to entries or an array of structures representing the entries.\nThe limitations of the Java language mean that entries are associated with the ring-buffer as pointers to objects.\nEach of these entries is typically not the data being passed itself, but a container for it.\nThis pre-allocation of entries eliminates issues in languages that support garbage collection, since the entries will be re-used and live for the duration of the Disruptor instance.\nThe memory for these entries is allocated at the same time and it is highly likely that it will be laid out contiguously in main memory and so support cache striding.\nThere is a proposal by John Rose to introduce \"`value types`\" footnote:valuetypes[Value Types - https://blogs.oracle.com/jrose/tuples-in-the-vm] to the Java language which would allow arrays of tuples, like other languages such as C, and so ensure that memory would be allocated contiguously and avoid the pointer indirection.\n\nGarbage collection can be problematic when developing low-latency systems in a managed runtime environment like Java.\nThe more memory that is allocated the greater the burden this puts on the garbage collector.\nGarbage collectors work at their best when objects are either very short-lived or effectively immortal.\nThe pre-allocation of entries in the ring buffer means that it is immortal as far as garbage collector is concerned and so represents little burden.\n\nUnder heavy load queue-based systems can back up, which can lead to a reduction in the rate of processing, and results in the allocated objects surviving longer than they should, thus being promoted beyond the young generation with generational garbage collectors.\nThis has two implications: first, the objects have to be copied between generations which cause latency jitter; second, these objects have to be collected from the old generation which is typically a much more expensive operation and increases the likelihood of \"`stop the world`\" pauses that result when the fragmented memory space requires compaction.\nIn large memory heaps this can cause pauses of seconds per GB in duration.\n\n=== Teasing Apart the Concerns\nWe saw the following concerns as being conflated in all queue implementations, to the extent that this collection of distinct behaviours tend to define the interfaces that queues implement:\n\n1. Storage of items being exchanged\n2. Coordination of producers claiming the next sequence for exchange\n3. Coordination of consumers being notified that a new item is available\n\nWhen designing a financial exchange in a language that uses garbage collection, too much memory allocation can be problematic.\nSo, as we have described linked-list backed queues are a not a good approach.\nGarbage collection is minimized if the entire storage for the exchange of data between processing stages can be pre-allocated.\nFurther, if this allocation can be performed in a uniform chunk, then traversal of that data will be done in a manner that is very friendly to the caching strategies employed by modern processors.\nA data-structure that meets this requirement is an array with all the slots pre-filled.\nOn creation of the ring buffer the Disruptor utilises the abstract factory pattern to pre-allocate the entries.\nWhen an entry is claimed, a producer can copy its data into the pre-allocated structure.\n\nOn most processors there is a very high cost for the remainder calculation on the sequence number, which determines the slot in the ring.\nThis cost can be greatly reduced by making the ring size a power of 2.\nA bit mask of size minus one can be used to perform the remainder operation efficiently.\n\nAs we described earlier bounded queues suffer from contention at the head and tail of the queue.\nThe ring buffer data structure is free from this contention and concurrency primitives because these concerns have been teased out into producer and consumer barriers through which the ring buffer must be accessed.\nThe logic for these barriers is described below.\n\nIn most common usages of the Disruptor there is usually only one producer.\nTypical producers are file readers or network listeners. In cases where there is a single producer there is no contention on sequence/entry allocation.\nIn more unusual usages where there are multiple producers, producers will race one another to claim the next entry in the ring-buffer.\nContention on claiming the next available entry can be managed with a simple CAS operation on the sequence number for that slot.\n\nOnce a producer has copied the relevant data to the claimed entry it can make it public to consumers by committing the sequence.\nThis can be done without CAS by a simple busy spin until the other producers have reached this sequence in their own commit.\nThen this producer can advance the cursor signifying the next available entry for consumption.\nProducers can avoid wrapping the ring by tracking the sequence of consumers as a simple read operation before they write to the ring buffer.\n\nConsumers wait for a sequence to become available in the ring buffer before they read the entry.\nVarious strategies can be employed while waiting.\nIf CPU resource is precious they can wait on a condition variable within a lock that gets signalled by the producers.\nThis obviously is a point of contention and only to be used when CPU resource is more important than latency or throughput.\nThe consumers can also loop checking the cursor which represents the currently available sequence in the ring buffer.\nThis could be done with or without a thread yield by trading CPU resource against latency.\nThis scales very well as we have broken the contended dependency between the producers and consumers if we do not use a lock and condition variable.\nLock free multi-producer – multi-consumer queues do exist but they require multiple CAS operations on the head, tail, size counters.\nThe Disruptor does not suffer this CAS contention.\n\n=== Sequencing\nSequencing is the core concept to how the concurrency is managed in the Disruptor.\nEach producer and consumer works off a strict sequencing concept for how it interacts with the ring buffer.\nProducers claim the next slot in sequence when claiming an entry in the ring.\nThis sequence of the next available slot can be a simple counter in the case of only one producer or an atomic counter updated using CAS operations in the case of multiple producers.\nOnce a sequence value is claimed, this entry in the ring buffer is now available to be written to by the claiming producer.\nWhen the producer has finished updating the entry it can commit the changes by updating a separate counter which represents the cursor on the ring buffer for the latest entry available to consumers.\nThe ring buffer cursor can be read and written in a busy spin by the producers using memory barrier without requiring a CAS operation as below.\n\n[source,java]\n----\nlong expectedSequence = claimedSequence – 1;\nwhile (cursor != expectedSequence)\n{\n  // busy spin\n}\n\ncursor = claimedSequence;\n----\n\nConsumers wait for a given sequence to become available by using a memory barrier to read the cursor.\nOnce the cursor has been updated the memory barriers ensure the changes to the entries in the ring buffer are visible to the consumers who have waited on the cursor advancing.\n\nConsumers each contain their own sequence which they update as they process entries from the ring buffer.\nThese consumer sequences allow the producers to track consumers to prevent the ring from wrapping.\nConsumer sequences also allow consumers to coordinate work on the same entry in an ordered manner\n\nIn the case of having only one producer, and regardless of the complexity of the consumer graph, no locks or CAS operations are required.\nThe whole concurrency coordination can be achieved with just memory barriers on the discussed sequences.\n\n=== Batching Effect\nWhen consumers are waiting on an advancing cursor sequence in the ring buffer an interesting opportunity arises that is not possible with queues.\nIf the consumer finds the ring buffer cursor has advanced a number of steps since it last checked it can process up to that sequence without getting involved in the concurrency mechanisms.\nThis results in the lagging consumer quickly regaining pace with the producers when the producers burst ahead thus balancing the system.\nThis type of batching increases throughput while reducing and smoothing latency at the same time.\nBased on our observations, this effect results in a close to constant time for latency regardless of load, up until the memory sub-system is saturated, and then the profile is linear following Little’s Law footnote:littleslaw[Little’s Law - https://en.wikipedia.org/wiki/Little%27s_law].\nThis is very different to the \"`J`\" curve effect on latency we have observed with queues as load increases.\n\n=== Dependency Graphs\nA queue represents the simple one step pipeline dependency between producers and consumers.\nIf the consumers form a chain or graph-like structure of dependencies then queues are required between each stage of the graph.\nThis incurs the fixed costs of queues many times within the graph of dependent stages.\nWhen designing the LMAX financial exchange our profiling showed that taking a queue based approach resulted in queuing costs dominating the total execution costs for processing a transaction.\n\nBecause the producer and consumer concerns are separated with the Disruptor pattern, it is possible to represent a complex graph of dependencies between consumers while only using a single ring buffer at the core.\nThis results in greatly reduced fixed costs of execution thus increasing throughput while reducing latency.\n\nA single ring buffer can be used to store entries with a complex structure representing the whole workflow in a cohesive place.\nCare must be taken in the design of such a structure so that the state written by independent consumers does not result in false sharing of cache lines.\n\n=== Disruptor Class Diagram\nThe core relationships in the Disruptor framework are depicted in the class diagram below.\nThis diagram leaves out the convenience classes which can be used to simplify the programming model.\nAfter the dependency graph is constructed the programming model is simple.\nProducers claim entries in sequence via a `ProducerBarrier`, write their changes into the claimed entry, then commit that entry back via the `ProducerBarrier` making them available for consumption.\nAs a consumer all one needs do is provide a `BatchHandler` implementation that receives call backs when a new entry is available.\nThis resulting programming model is event based having a lot of similarities to the Actor Model.\n\nSeparating the concerns normally conflated in queue implementations allows for a more flexible design.\nA `RingBuffer` exists at the core of the Disruptor pattern providing storage for data exchange without contention.\nThe concurrency concerns are separated out for the producers and consumers interacting with the `RingBuffer`.\nThe `ProducerBarrier` manages any concurrency concerns associated with claiming slots in the ring buffer, while tracking dependant consumers to prevent the ring from wrapping.\nThe `ConsumerBarrier` notifies consumers when new entries are available, and Consumers can be constructed into a graph of dependencies representing multiple stages in a processing pipeline.\n\nimage::./resources/images/classdiagram.png[]\n\n=== Code Example\nThe code below is an example of a single producer and single consumer using the convenience interface `BatchHandler` for implementing a consumer.\nThe consumer runs on a separate thread receiving entries as they become available.\n\n[source,java]\n----\n// Callback handler which can be implemented by consumers\nfinal BatchHandler<ValueEntry> batchHandler = new BatchHandler<ValueEntry>()\n{\npublic void onAvailable(final ValueEntry entry) throws Exception\n{\n// process a new entry as it becomes available.\n}\n\n    public void onEndOfBatch() throws Exception\n    {\n        // useful for flushing results to an IO device if necessary.\n    }\n\n    public void onCompletion()\n    {\n        // do any necessary clean up before shutdown\n    }\n};\n\nRingBuffer<ValueEntry> ringBuffer =\n    new RingBuffer<ValueEntry>(ValueEntry.ENTRY_FACTORY, SIZE,\n                               ClaimStrategy.Option.SINGLE_THREADED,\n                               WaitStrategy.Option.YIELDING);\nConsumerBarrier<ValueEntry> consumerBarrier = ringBuffer.createConsumerBarrier();\nBatchConsumer<ValueEntry> batchConsumer =\n    new BatchConsumer<ValueEntry>(consumerBarrier, batchHandler);\nProducerBarrier<ValueEntry> producerBarrier = ringBuffer.createProducerBarrier(batchConsumer);\n\n// Each consumer can run on a separate thread\nEXECUTOR.submit(batchConsumer);\n\n// Producers claim entries in sequence\nValueEntry entry = producerBarrier.nextEntry();\n\n// copy data into the entry container\n\n// make the entry available to consumers\nproducerBarrier.commit(entry);\n----\n\n== Throughput Performance Testing\nAs a reference we choose Doug Lea’s excellent ``java.util.concurrent.ArrayBlockingQueue``footnote:arrayblockingqueue[ArrayBlockingQueue - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ArrayBlockingQueue.html] which has the highest performance of any bounded queue based on our testing.\nThe tests are conducted in a blocking programming style to match that of the Disruptor.\nThe tests cases detailed below are available in the Disruptor open source project.\n\nWARNING: running the tests requires a system capable of executing at least 4 threads in parallel.\n\n.Unicast: 1P – 1C\nimage::./resources/images/unicast1p1c.png[]\n\n.Three Step Pipeline: 1P – 3C\nimage::./resources/images/threestep1p3c.png[]\n\n.Sequencer: 3P – 1C\nimage::./resources/images/sequencer3p1c.png[]\n\n.Multicast: 1P – 3C\nimage::./resources/images/multicast1p3c.png[]\n\n.Diamond: 1P – 3C\nimage::./resources/images/diamond1p3c.png[]\n\nFor the above configurations an `ArrayBlockingQueue` was applied for each arc of data flow compared to barrier configuration with the Disruptor.\nThe following table shows the performance results in operations per second using a Java 1.6.0_25 64-bit Sun JVM, Windows 7, Intel Core i7 860 @ 2.8 GHz without HT and Intel Core i7-2720QM, Ubuntu 11.04, and taking the best of 3 runs when processing 500 million messages.\nResults can vary substantially across different JVM executions and the figures below are not the highest we have observed.\n\n.Comparative throughput (in ops per sec)\n[cols=5*,options=\"header\"]\n|===\n|\n2+| Nehalem 2.8Ghz – Windows 7 SP1 64-bit\n2+| Sandy Bridge 2.2Ghz – Linux 2.6.38 64-bit\n\n|\nh| ABQ\nh| Disruptor\nh| ABQ\nh| Disruptor\n\n| Unicast: 1P – 1C\n| 5,339,256\n| 25,998,336\n| 4,057,453\n| 22,381,378\n\n| Pipeline: 1P – 3C\n| 2,128,918\n| 16,806,157\n| 2,006,903\n| 15,857,913\n\n| Sequencer: 3P – 1C\n| 5,539,531\n| 13,403,268\n| 2,056,118\n| 14,540,519\n\n| Multicast: 1P – 3C\n| 1,077,384\n| 9,377,871\n| 260,733\n| 10,860,121\n\n| Diamond: 1P – 3C\n| 2,113,941\n| 16,143,613\n| 2,082,725\n| 15,295,197\n|===\n\n.Comparative throughput updated for modern hardware (in ops per sec)\n[cols=4*,options=\"header\"]\n|===\n|\n3+| AMD EPYC 9374F – Linux 5.4.277 – OpenJDK 11.0.24\n\n|\nh| ABQ\nh| Disruptor 3\nh| Disruptor 4\n\n| Unicast: 1P – 1C\n| 20,895,148\n| 134,553,283\n| 160,359,204\n\n| Pipeline: 1P – 3C\n| 5,216,647\n| 76,068,766\n| 101,317,122\n\n| Sequencer: 3P – 1C\n| 18,791,340\n| 16,010,759\n| 29,726,516\n\n| Multicast: 1P – 3C\n| 2,355,379\n| 68,157,033\n| 70,018,204\n\n| Diamond: 1P – 3C\n| 3,433,665\n| 61,229,488\n| 63,123,343\n|===\n\n== Latency Performance Testing\nTo measure latency we take the three stage pipeline and generate events at less than saturation.\nThis is achieved by waiting 1 microsecond after injecting an event before injecting the next and repeating 50 million times.\nTo time at this level of precision it is necessary to use time stamp counters from the CPU.\nWe chose CPUs with an invariant TSC because older processors suffer from changing frequency due to power saving and sleep states.\nIntel Nehalem and later processors use an invariant TSC which can be accessed by the latest Oracle JVMs running on Ubuntu 11.04.\nNo CPU binding has been employed for this test.\nFor comparison we use the ArrayBlockingQueue once again.\nWe could have used ConcurrentLinkedQueue footnote:CLQ[ConcurrentLinkedQueue - http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html] which is likely to give better results but we want to use a bounded queue implementation to ensure producers do not outpace consumers by creating back pressure.\nThe results below are for 2.2Ghz Core i7-2720QM running Java 1.6.0_25 64-bit on Ubuntu 11.04.\nMean latency per hop for the Disruptor comes out at 52 nanoseconds compared to 32,757 nanoseconds for ArrayBlockingQueue.\nProfiling shows the use of locks and signalling via a condition variable are the main cause of latency for the ArrayBlockingQueue.\n\n.Comparative Latency in three stage pipeline\n[cols=3*,options=\"header\"]\n|===\n| | Array Blocking Queue (ns) | Disruptor (ns)\n\n| Min Latency\n| 145\n| 29\n\n| Mean Latency\n| 32,757\n| 52\n\n| 99% observations less than\n| 2,097,152\n| 128\n\n| 99.99% observations less than\n| 4,194,304\n| 8,192\n\n| Max Latency\n| 5,069,086\n| 175,567\n|===\n\n== Conclusion\nThe Disruptor is a major step forward for increasing throughput, reducing latency between concurrent execution contexts and ensuring predictable latency, an important consideration in many applications.\nOur testing shows that it out-performs comparable approaches for exchanging data between threads.\nWe believe that this is the highest performance mechanism for such data exchange.\nBy concentrating on a clean separation of the concerns involved in cross-thread data exchange, by eliminating write contention, minimizing read contention and ensuring that the code worked well with the caching employed by modern processors, we have created a highly efficient mechanism for exchanging data between threads in any application.\n\nThe batching effect that allows consumers to process entries up to a given threshold, without any contention, introduces a new characteristic in high performance systems.\nFor most systems, as load and contention increase there is an exponential increase in latency, the characteristic \"`J`\" curve.\nAs load increases on the Disruptor, latency remains almost flat until saturation occurs of the memory sub-system.\n\nWe believe that the Disruptor establishes a new benchmark for high-performance computing and is very well placed to continue to take advantage of current trends in processor and computer design.\n\nView the original PDF of this paper link:./files/Disruptor-1.0.pdf[here].\n"
  },
  {
    "path": "src/docs/asciidoc/en/index.adoc",
    "content": "= LMAX Disruptor\nHigh Performance Inter-Thread Messaging Library\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\n// If you're changing these, also check out asciidoctor.gradle!\n:xrefstyle: short\n:icons: font\n:gradle-rootdir: ../../../../\n:imagesdir: ../../\n\n== Read This First\n\nTo understand the problem the Disruptor is trying to solve, and to get a feel for why this concurrency framework is so fast, read the <<disruptor.adoc#,Technical Paper>>.\nIt also contains detailed performance results.\n\nAnd now for some words from our sponsors...\n\nLMAX are recruiting once again.\nIf you are interested in working with a great team, with some amazing technology, and think you can add something to the mix then please check out our https://careers.lmax.com/[jobs page].\n\n== What is the Disruptor?\n\nhttps://www.lmax.com[LMAX] aims to be the fastest trading platform in the world.\nClearly, in order to achieve this we needed to do something special to achieve very low-latency and high-throughput with our Java platform.\nPerformance testing showed that using queues to pass data between stages of the system was introducing latency, so we focused on optimising this area.\n\nThe Disruptor is the result of our research and testing.\nWe found that cache misses at the CPU-level, and locks requiring kernel arbitration are both extremely costly, so we created a framework which has \"mechanical sympathy\" for the hardware it's running on, and that's lock-free.\n\nThis is not a specialist solution, it's not designed to work only for a financial application.\nThe Disruptor is a general-purpose mechanism for solving a difficult problem in concurrent programming.\n\nIt works in a different way to more conventional approaches, so you use it a little differently than you might be used to.\nFor example, applying the pattern to your system is not as simple as replacing all your queues with the https://trishagee.com/2011/06/22/dissecting_the_disruptor_whats_so_special_about_a_ring_buffer/[magic ring buffer].\nWe've got:\n\n- a <<user-guide/index.adoc#,User Guide>> to guide you,\n- a growing number of https://github.com/LMAX-Exchange/disruptor/wiki/Blogs-And-Articles[blogs and articles] giving an overview of how it works,\n- the <<disruptor.adoc#,technical paper>> goes into some detail as you'd expect,\n- and the performance tests give examples of how to use the Disruptor.\n\nIf you prefer real, live people explaining things instead of a dry paper or content-heavy website, there's always the https://www.infoq.com/presentations/LMAX/[presentation Mike and Martin gave] at QCon San Francisco.\nIf you fancy a natter with the folks involved head over to our https://groups.google.com/g/lmax-disruptor[Discussion Group].\nMartin Thompson will also witter on occasionally about performance in his https://mechanical-sympathy.blogspot.com/[Mechanical Sympathy blog].\nMartin Fowler has also done a great https://martinfowler.com/articles/lmax.html[review] of the Disruptor's application at LMAX.\n\n== What's the big deal?\n\nIt's fast.\nVery fast.\n\n.Latency histogram comparing Disruptor to ArrayBlockingQueue\nimage::resources/images/latency-histogram.png[]\n\nNote that this is a log-log scale, not linear.\nIf we tried to plot the comparisons on a linear scale, we'd run out of space very quickly.\nWe have performance results of the test that produced these results, plus others of throughput testing.\n\n== Great What do I do next?\n\n- Read the <<user-guide/index.adoc#,User Guide>>,\n- Read the <<./javadoc/index#,API documentation>>,\n- Check out our https://github.com/LMAX-Exchange/disruptor/wiki/Frequently-Asked-Questions[Frequently Asked Questions]\n- Want to work on the Disruptor? Read the <<developer-guide/index.adoc#,Developer Guide>>,\n\n== Discussion, Blogs & Other Useful Links\n\n- https://groups.google.com/g/lmax-disruptor[Disruptor Google Group]\n- <<disruptor.adoc#,Disruptor Paper>>\n- https://martinfowler.com/articles/lmax.html[Martin Fowler's Technical Review]\n- https://github.com/disruptor-net/Disruptor-net[.NET Disruptor Port]\n- https://www.lmax.com[LMAX Exchange]\n- https://www.lmax.com/blog/staff-blogs/[LMAX Staff Blogs]\n- https://mechanical-sympathy.blogspot.com/[Mechanical Sympathy] (Martin Thompson)\n- https://bad-concurrency.blogspot.com/[Bad Concurrency] (Michael Barker)\n\n== Presentations\n\n- https://www.infoq.com/presentations/LMAX/[Disruptor presentation @ QCon SF]\n- https://www.slideshare.net/trishagee/introduction-to-the-disruptor[Introduction to the Disruptor]\n\n== Changelog\n\nThe changelog can be <<changelog.adoc#,found here>>."
  },
  {
    "path": "src/docs/asciidoc/en/user-guide/10_using_the_disruptor.adoc",
    "content": "= Using the Disruptor\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\n// If you're changing these, also check out asciidoctor.gradle!\n:xrefstyle: short\n:icons: font\n:gradle-rootdir: ../../../../../\n:imagesdir: ../../\n\n== Introduction\n\nThe Disruptor is a library that provides a concurrent ring buffer data structure.\nIt is designed to provide a low-latency, high-throughput work queue in asynchronous event processing architectures.\n\nTo understand the benefits of the Disruptor we can compare it to something well understood and quite similar in purpose.\nIn the case of the Disruptor this would be Java's `BlockingQueue`.\nLike a queue the purpose of the Disruptor is to move data (e.g. messages or events) between threads within the same process.\nHowever, there are some key features that the Disruptor provides that distinguish it from a queue.\nThey are:\n\n- Multicast events to consumers, with <<_consumer_dependency_graph,consumer dependency graph>>.\n- <<_event_pre_allocation, Pre-allocate memory>> for events.\n- <<_optionally_lock_free, Optionally lock-free>>.\n\n=== Core Concepts\n\nBefore we can understand how the Disruptor works, it is worthwhile defining a number of terms that will be used throughout the documentation and the code.\nFor those with a DDD bent, think of this as the ubiquitous language of the Disruptor domain.\n\n- **Ring Buffer**: The Ring Buffer is often considered the main aspect of the Disruptor.\nHowever, from 3.0 onwards, the Ring Buffer is only responsible for the storing and updating of the data (``Event``s) that move through the Disruptor.\nFor some advanced use cases, it can even be completely replaced by the user.\n\n- *Sequence*: The Disruptor uses ``Sequence``s as a means to identify where a particular component is up to.\nEach consumer (Event Processor) maintains a `Sequence` as does the Disruptor itself.\nThe majority of the concurrent code relies on the movement of these Sequence values, hence the `Sequence` supports many of the current features of an `AtomicLong`.\nIn fact the only real difference between the two is that the `Sequence` contains additional functionality to prevent false sharing between ``Sequence``s and other values.\n\n- *Sequencer*: The Sequencer is the real core of the Disruptor.\nThe two implementations (single producer, multi producer) of this interface implement all the concurrent algorithms for fast, correct passing of data between producers and consumers.\n\n- *Sequence Barrier*: The Sequencer produces a Sequence Barrier that contains references to the main published `Sequence` from the Sequencer and the ``Sequence``s of any dependent consumer.\nIt contains the logic to determine if there are any events available for the consumer to process.\n\n- *Wait Strategy*: The Wait Strategy determines how a consumer will wait for events to be placed into the Disruptor by a producer.\nMore details are available in the section about being optionally lock-free.\n\n- *`Event`*: The unit of data passed from producer to consumer.\nThere is no specific code representation of the Event as it defined entirely by the user.\n\n- *Event Processor*: The main event loop for handling events from the Disruptor and has ownership of consumer's Sequence.\nThere is a single representation called BatchEventProcessor that contains an efficient implementation of the event loop and will call back onto a user supplied implementation of the EventHandler interface.\n\n- *Event Handler*: An interface that is implemented by the user and represents a consumer for the Disruptor.\n\n- *Producer*: This is the user code that calls the Disruptor to enqueue ``Event``s.\nThis concept also has no representation in the code.\n\nTo put these elements into context, below is an example of how LMAX uses the Disruptor within its high performance core services, e.g. the exchange.\n\n[#user-guide-models]\n.Disruptor with a set of dependent consumers.\nimage::../resources/images/user-guide/models.png[]\n\n=== Multicast Events\n\nThis is the biggest behavioural difference between queues and the Disruptor.\n\nWhen you have multiple consumers listening on the same Disruptor, it publishes all events to all consumers.\nIn contrast, a queue will only send a single event to a single consumer.\nYou can use this behaviour of the Disruptor when you need to independent multiple parallel operations on the same data.\n\n.Example use-case\n[example]\n****\nThe canonical example from LMAX is where we have three operations:\n- journalling (writing the input data to a persistent journal file);\n- replication (sending the input data to another machine to ensure that there is a remote copy of the data);\n- and business logic (the real processing work).\n\nLooking at <<user-guide-models>> is possible to see that there are 3 ``EventHandler``s listening (`JournalConsumer`, `ReplicationConsumer` and `ApplicationConsumer`) to the Disruptor.\nEach of these Event Handlers will receive *all* the messages available in the Disruptor (in the same order).\nThis allows for work for each of these consumers to operate in parallel.\n****\n\n[#_consumer_dependency_graph]\n=== Consumer Dependency Graph\n\nTo support real world applications of the parallel processing behaviour it was necessary to support co-ordination between the consumers.\nReferring back to the example described above, it is necessary to prevent the business logic consumer from making progress until the journalling and replication consumers have completed their tasks.\nWe call this concept \"`gating`\" (or, more correctly, the feature is a form of \"`gating`\").\n\n\"`Gating`\" happens in two places:\n\n- Firstly we need to ensure that the producers do not overrun consumers.\nThis is handled by adding the relevant consumers to the Disruptor by calling `RingBuffer.addGatingConsumers()`.\n\n- Secondly, the case referred to previously is implemented by constructing a SequenceBarrier containing Sequences from the components that must complete their processing first.\n\nReferring to <<user-guide-models>> there are 3 consumers listening for Events from the Ring Buffer.\nThere is a dependency graph in this example.\n\nThe ApplicationConsumer depends on the `JournalConsumer` and `ReplicationConsumer`.\nThis means that the `JournalConsumer` and `ReplicationConsumer` can run freely in parallel with each other.\nThe dependency relationship can be seen by the connection from the ``ApplicationConsumer``'s `SequenceBarrier` to the ``Sequence``s of the `JournalConsumer` and `ReplicationConsumer`.\n\nIt is also worth noting the relationship that the `Sequencer` has with the downstream consumers.\nOne of its roles is to ensure that publication does not wrap the Ring Buffer.\nTo do this none of the downstream consumer may have a `Sequence` that is lower than the Ring Buffer's `Sequence` less the size of the Ring Buffer.\n\nHowever, by using the graph of dependencies an interesting optimisation can be made.\nBecause the ``ApplicationConsumer``'s Sequence is guaranteed to be less than or equal to that of the `JournalConsumer` and `ReplicationConsumer` (that is what that dependency relationship ensures) the `Sequencer` need only look at the Sequence of the `ApplicationConsumer`.\nIn a more general sense the `Sequencer` only needs to be aware of the ``Sequence``s of the consumers that are the leaf nodes in the dependency tree.\n\n[#_event_pre_allocation]\n=== Event Pre-allocation\n\nOne of the goals of the Disruptor is to enable use within a low latency environment.\nWithin low-latency systems it is necessary to reduce or remove memory allocations.\nIn Java-based system the purpose is to reduce the number stalls due to garbage collection footnote:low-latency[in low-latency C/C++ systems,heavy memory allocation is also problematic due to the contention that be placed on the memory allocator].\n\nTo support this the user is able to preallocate the storage required for the events within the Disruptor.\nDuring construction and `EventFactory` is supplied by the user and will be called for each entry in the Disruptor's Ring Buffer.\nWhen publishing new data to the Disruptor the API will allow the user to get hold of the constructed object so that they can call methods or update fields on that store object.\nThe Disruptor provides guarantees that these operations will be concurrency-safe as long as they are implemented correctly.\n\n[#_optionally_lock_free]\n=== Optionally Lock-free\n\nAnother key implementation detail pushed by the desire for low-latency is the extensive use of lock-free algorithms to implement the Disruptor.\nAll memory visibility and correctness guarantees are implemented using memory barriers and/or compare-and-swap operations.\n\n[CAUTION]\n--\nThere is only one use-case where an actual lock is required and that is within the `BlockingWaitStrategy`.\n\nThis is done solely for the purpose of using a *condition* so that a consuming thread can be parked while waiting for new events to arrive.\nMany low-latency systems will use a busy-wait to avoid the jitter that can be incurred by using a *condition*; however, in number of system busy-wait operations can lead to significant degradation in performance, especially where the CPU resources are heavily constrained, e.g. web servers in virtualised-environments.\n--\n\n== Getting Started\n\n=== Getting the Disruptor\n\nThe Disruptor jar file is available from https://search.maven.org/artifact/com.lmax/disruptor[Maven Central] and can be integrated into your dependency manager of choice from there.\n\n=== Basic Produce and Consume\n\nTo get started with the Disruptor we are going to consider very simple and contrived example.\nWe will pass a single `long` value from a producer to a consumer, and the consumer will simply print out the value.\n\nThere are currently several styles of writing publishers and consumers for the Disruptor.\nWhilst they are all fundamentally similar, there may be slight nuances in each approach that will be covered below.\n\nFirstly we will define the `Event` that will carry the data and is common to all following examples:\n\n.Example `LongEvent`\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/longevent/LongEvent.java[tag=example]\n----\n\nIn order to allow the Disruptor to preallocate these events for us, we need to an `EventFactory` that will perform the construction.\nThis could be a method reference, such as `LongEvent::new` or an explicit implementation of the `EventFactory` interface:\n\n.Example `LongEventFactory`\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/longevent/LongEventFactory.java[tag=example]\n----\n\nOnce we have the event defined, we need to create a consumer that will handle these events.\nAs an example, we will create an `EventHandler` that will print the value out to the console.\n\n.Example `LongEventHandler`\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/longevent/LongEventHandler.java[tag=example]\n----\n\nFinally, we will need a source for these events.\nFor simplicity, we will assume that the data is coming from some sort of I/O device, e.g. network or file in the form of a `ByteBuffer`.\n\n==== Publishing\n\n[[publishing-using-lambdas]]\n===== Using Lambdas\n\nSince version 3.0 of the Disruptor it has been possible to use a Lambda-style API to write publishers.\nThis is the preferred approach, as it encapsulates much of the complexity of the alternatives.\n\n.Publishing events using lambdas\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/longevent/lambdas/LongEventMain.java[tag=example]\n----\n<1> Specify the size of the ring buffer, must be power of 2.\n<2> Construct the Disruptor\n<3> Connect the handler\n<4> Start the Disruptor, starts all threads running\n<5> Get the ring buffer from the Disruptor to be used for publishing.\n\n[WARNING]\n--\nNotice that the lambda used for `publishEvent()` only refers to the parameters that are passed in.\n\nIf we were to instead write that code as:\n\n.Example of a capturing lambda\n[source,java]\n----\nByteBuffer bb = ByteBuffer.allocate(8);\nfor (long l = 0; true; l++)\n{\n    bb.putLong(0, l);\n    ringBuffer.publishEvent((event, sequence) -> event.set(bb.getLong(0)));\n    Thread.sleep(1000);\n}\n----\n\nThis would create a capturing lambda, meaning that it would need to instantiate an object to hold the `ByteBuffer bb` variable as it passes the lambda through to the `publishEvent()` call.\nThis will create additional (unnecessary) garbage, so the call that passes the argument through to the lambda should be preferred if low GC pressure is a requirement.\n--\n\nGiven that method references can be used instead of anonymous lambdas, it is possible to rewrite the example in this fashion:\n\n.Example using method references\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/longevent/methodrefs/LongEventMain.java[tag=example]\n----\n\n===== Using Translators\n\nPrior to version 3.0, the preferred way of publishing messages was via the Event Publisher/Event Translator interfaces:\n\n.Example `LongEventProducer`\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/longevent/LongEventProducer.java[tag=example]\n----\n\nThis approach uses number of extra classes (e.g. handler, translator) that are not explicitly required when using lambdas.\nThe advantage of here is that the translator code can be pulled into a separate class and easily unit tested.\n\nThe Disruptor provides a number of different interfaces (`EventTranslator`, `EventTranslatorOneArg`, `EventTranslatorTwoArg`, etc.) that can be implemented to provide translators.\nThis is to allow for the translators to be represented as static classes and lambdas (see <<publishing-using-lambdas,above>>).\nThe arguments to the translation method are passed through the call on the Ring Buffer through to the translator.\n\n==== Publishing Using the Legacy API\n\nThere is a more \"raw\" approach that we can use:\n\n.Example Legacy `LongEventProducer`\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/longevent/legacy/LongEventProducer.java[tag=example]\n----\n<1> Grab the next sequence\n<2> Get the entry in the Disruptor for that sequence\n<3> Fill the entry with data\n\nWhat becomes immediately obvious is that event publication becomes more involved than using a simple queue.\nThis is due to the desire for Event pre-allocation.\nIt requires (at the lowest level) a 2-phase approach to message publication, i.e. claim the slot in the ring buffer and then publish the available data.\n\n[CAUTION]\n--\nIt is also necessary to wrap publication in a `try`/`finally` block.\n\nIf we claim a slot in the Ring Buffer (calling ``RingBuffer#next()``) then we must publish this sequence.\nFailing to do so can result in corruption of the state of the Disruptor.\n\nSpecifically, in the multi-producer case, this will result in the consumers stalling and being unable to recover without a restart.\nTherefore, it is recommended that either the lambda or `EventTranslator` APIs be used.\n--\n\nThe final step is to wire the whole thing together.\nWhilst it is possible to wire up each component manually, this can be complicated and so a DSL is provided to simplify construction.\n\nTIP: Some of the more complicated options are not available via the DSL; however, it is suitable for most circumstances.\n\n.Example using the legacy `LongEventProducer`\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/longevent/legacy/LongEventMain.java[tag=example]\n----\n\n=== Basic Tuning Options\n\nUsing the above approach will work functionally in the widest set of deployment scenarios.\nHowever, there are a number of tuning options that can be used to improve performance.\n\nThe two main options for tuning are:\n\n- <<_single_vs_multiple_producers, Single vs. multiple producers>>, _and_\n- <<_alternative_wait_strategies, Alternative wait strategies>>.\n\nBoth of these options are set when constructing a Disruptor:\n\n.Tuning the Disruptor\n[source,java]\n----\npublic class LongEventMain\n{\n    public static void main(final String[] args)\n    {\n        //.....\n        Disruptor<LongEvent> disruptor = new Disruptor(\n            factory,\n            bufferSize,\n            DaemonThreadFactory.INSTANCE,\n            ProducerType.SINGLE, // <1>\n            new BlockingWaitStrategy() // <2>\n        );\n        //.....\n    }\n}\n----\n<1> Use `ProducerType#SINGLE` to create a `SingleProducerSequencer`; use `ProducerType#MULTI` to create a `MultiProducerSequence`\n<2> Set the desired `WaitStrategy`\n\n\n[#_single_vs_multiple_producers]\n==== Single vs. Multiple Producers\n\nOne of the best ways to improve performance in concurrent systems is to adhere to the https://mechanical-sympathy.blogspot.com/2011/09/single-writer-principle.html[Single Writer Principle], this applies to the Disruptor.\nIf you are in the situation where there will only ever be a single thread producing events into the Disruptor, then you can take advantage of this to gain additional performance.\n\nTo give an indication of how much of a performance advantage can be achieved through this technique we can change the producer type in the OneToOne performance test.\nTests run on i7 Sandy Bridge MacBook Air.\n\n.Multiple Producer\n[%autowidth]\n|===\n| Run 0 | Disruptor=26,553,372 ops/sec\n| Run 1 | Disruptor=28,727,377 ops/sec\n| Run 2 | Disruptor=29,806,259 ops/sec\n| Run 3 | Disruptor=29,717,682 ops/sec\n| Run 4 | Disruptor=28,818,443 ops/sec\n| Run 5 | Disruptor=29,103,608 ops/sec\n| Run 6 | Disruptor=29,239,766 ops/sec\n|===\n\n.Single Producer\n[%autowidth]\n|===\n| Run 0 | Disruptor=89,365,504 ops/sec\n| Run 1 | Disruptor=77,579,519 ops/sec\n| Run 2 | Disruptor=78,678,206 ops/sec\n| Run 3 | Disruptor=80,840,743 ops/sec\n| Run 4 | Disruptor=81,037,277 ops/sec\n| Run 5 | Disruptor=81,168,831 ops/sec\n| Run 6 | Disruptor=81,699,346 ops/sec\n|===\n\n[#_alternative_wait_strategies]\n==== Alternative Wait Strategies\n\nThe default `WaitStrategy` used by the Disruptor is the `BlockingWaitStrategy`.\nInternally the `BlockingWaitStrategy` uses a typical lock and condition variable to handle thread wake-up.\nThe `BlockingWaitStrategy` is the slowest of the available wait strategies, but is the most conservative with the respect to CPU usage and will give the most consistent behaviour across the widest variety of deployment options.\n\nKnowledge of the deployed system can allow for additional performance by choosing a more appropriate wait strategy:\n\n- **SleepingWaitStrategy** ->\n\n--\nLike the `BlockingWaitStrategy` the `SleepingWaitStrategy` it attempts to be conservative with CPU usage by using a simple busy wait loop.\nThe difference is that the `SleepingWaitStrategy` uses a call to link:https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/locks/LockSupport.html#parkNanos(long)[`LockSupport.parkNanos(1)`^] in the middle of the loop.\nOn a typical Linux system this will pause the thread for around 60µs.\n\nThis has the benefits that the producing thread does not need to take any action other increment the appropriate counter and that it does not require the cost of signalling a condition variable.\nHowever, the mean latency of moving the event between the producer and consumer threads will be higher.\n\nIt works best in situations where low latency is not required, but a low impact on the producing thread is desired.\nA common use case is for asynchronous logging.\n--\n\n- **YieldingWaitStrategy** ->\n\n--\nThe `YieldingWaitStrategy` is one of two ``WaitStrategy``s that can be use in low-latency systems.\nIt is designed for cases where there is the option to burn CPU cycles with the goal of improving latency.\n\nThe `YieldingWaitStrategy` will busy spin, waiting for the sequence to increment to the appropriate value.\nInside the body of the loop `Thread#yield()` will be called allowing other queued threads to run.\n\nThis is the recommended wait strategy when you need very high performance, and the number of `EventHandler` threads is lower than the total number of logical cores, e.g. you have hyper-threading enabled.\n--\n\n- **BusySpinWaitStrategy** ->\n\n--\nThe `BusySpinWaitStrategy` is the highest performing `WaitStrategy`.\nLike the `YieldingWaitStrategy`, it can be used in low-latency systems, but puts the highest constraints on the deployment environment.\n\nThis wait strategy should only be used if the number of `EventHandler` threads is lower than the number of physical cores on the box, e.g. hyper-threading should be disabled.\n--\n\n=== Clearing Objects From the Ring Buffer\n\nWhen passing data via the Disruptor, it is possible for objects to live longer than intended.\nTo avoid this happening it may be necessary to clear out the event after processing it.\n\nIf you have a single event handler, clearing out the value within the same handler is sufficient.\nIf you have a chain of event handlers, then you may need a specific handler placed at the end of the chain to handle clearing out the object.\n\n.Example `ObjectEvent`\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/objectevent/ObjectEvent.java[tag=example]\n----\n\n.Example `ClearingEventHandler`\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/objectevent/ClearingEventHandler.java[tag=example]\n----\n<1> Failing to call `clear()` here will result in the object associated with the event to live until it is overwritten.\nThis will only happen once the ring buffer has wrapped around to the beginning.\n\n.Example using the `ClearingEventHandler`\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/objectevent/Main.java[tag=example]\n----\n\n== Advanced Techniques\n\n=== Dealing With Large Batches\n\n.Example of \"Early Release\"\n[source,java]\n----\ninclude::{gradle-rootdir}/src/examples/java/com/lmax/disruptor/examples/EarlyReleaseHandler.java[tag=example]\n----\n"
  },
  {
    "path": "src/docs/asciidoc/en/user-guide/20_design_and_implementation.adoc",
    "content": "= Design and Implementation\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\n// If you're changing these, also check out asciidoctor.gradle!\n:xrefstyle: short\n:icons: font\n\n- Single Producer Algorithm\n- Multiple Producer Algorithm\n"
  },
  {
    "path": "src/docs/asciidoc/en/user-guide/30_known_issues.adoc",
    "content": "= Known Issues\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\n// If you're changing these, also check out asciidoctor.gradle!\n:xrefstyle: short\n:icons: font\n\n- On 32 bit Linux systems it appears that `LockSupport.parkNanos()` is quite expensive, therefore using the `SleepingWaitStrategy` is not recommended.\n"
  },
  {
    "path": "src/docs/asciidoc/en/user-guide/40_batch_rewind_use_case.adoc",
    "content": "= Batch Rewind\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\n== The Feature\n\nWhen using the `BatchEventProcessor` to handle events as batches, there is a feature available that can be used to recover from an exception named \"Batch Rewind\".\n\nIf something goes wrong while handling an event that is recoverable, the user can throw a `RewindableException`. This will invoke the `BatchRewindStrategy` instead of the usual `ExceptionHandler` to decide whether the sequence number should rewind back to the beginning of the batch to be reattempted or rethrow and delegate to the `ExceptionHandler`.\n\ne.g.\n\nWhen using the `SimpleBatchRewindStrategy` (which will always rewind) then the `BatchEventProcessor` receives a batch from 150 -> 155, but a temporary failure happens on sequence 153 (which throws a `RewindableException`). The events processed will look like the following...\n\n```\n150, 151, 152, 153(failed -> rewind), 150, 151, 152, 153(succeeded this time), 154, 155\n```\n\nThe default `BatchRewindStrategy` is the `SimpleBatchRewindStrategy` but different strategies can be provided to the `BatchEventProcessor` like so...\n\n```\n        batchEventProcessor.setRewindStrategy(batchRewindStrategy);\n```\n\n== Use Case\n\nThis can be very useful when batches are handled as database transactions. So the start of a batch starts a transaction, events are handled as statements, and only committed at the end of a batch.\n\n\nHappy case\n```\nBatch start -> START TRANSACTION;\nEvent 1 ->     insert a row;\nEvent 2 ->     insert a row;\nEvent 3 ->     insert a row;\nBatch end ->   COMMIT;\n```\n\nSad case without Batch Rewind\n```\nBatch start -> START TRANSACTION;\nEvent 1 ->     insert a row;\nEvent 2 ->     DATABASE has a blip and can not commit\nThrow error -> ROLLBACK;\nUser needs to explcitily reattempt the batch or choose to abandon the batch\n```\n\nSad case with Batch Rewind\n```\nBatch start ->               START TRANSACTION;\nEvent 1 ->                   insert a row;\nEvent 2 ->                   DATABASE has a blip and can not insert\nThrow RewindableException -> ROLLBACK;\nBatch start ->               START TRANSACTION;\nEvent 1 ->                   insert a row;\nEvent 2 ->                   insert a row;\nEvent 3 ->                   insert a row;\nBatch end ->                 COMMIT;\n```\n\n"
  },
  {
    "path": "src/docs/asciidoc/en/user-guide/index.adoc",
    "content": "= LMAX Disruptor User Guide\n\n:Author: LMAX Development Team\n:Email:\n:Date: {docdata}\n\n// If you're changing these, also check out asciidoctor.gradle!\n:xrefstyle: short\n:icons: font\n:gradle-rootdir: ../../../../../\n:imagesdir: ../../\n\nThe LMAX Disruptor is a high performance inter-thread messaging library. It grew out of LMAX's research into concurrency, performance and non-blocking algorithms and today forms a core part of their Exchange's infrastructure.\n\n// Leave some gaps between these includes (trust me)\n\ninclude::10_using_the_disruptor.adoc[leveloffset=+1]\n\ninclude::20_design_and_implementation.adoc[leveloffset=+1]\n\ninclude::30_known_issues.adoc[leveloffset=+1]\n\ninclude::40_batch_rewind_use_case.adoc[leveloffset=+1]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/DynamicallyAddHandler.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.examples.support.StubEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\npublic class DynamicallyAddHandler\n{\n    private static class DynamicHandler implements EventHandler<StubEvent>\n    {\n        private final CountDownLatch shutdownLatch = new CountDownLatch(1);\n\n        @Override\n        public void onEvent(final StubEvent event, final long sequence, final boolean endOfBatch)\n        {\n        }\n\n        @Override\n        public void onStart()\n        {\n\n        }\n\n        @Override\n        public void onShutdown()\n        {\n            shutdownLatch.countDown();\n        }\n\n        public void awaitShutdown() throws InterruptedException\n        {\n            shutdownLatch.await();\n        }\n    }\n\n    public static void main(final String[] args) throws InterruptedException\n    {\n        ExecutorService executor = Executors.newCachedThreadPool(DaemonThreadFactory.INSTANCE);\n\n        // Build a disruptor and start it.\n        Disruptor<StubEvent> disruptor = new Disruptor<>(\n                StubEvent.EVENT_FACTORY, 1024, DaemonThreadFactory.INSTANCE);\n        RingBuffer<StubEvent> ringBuffer = disruptor.start();\n\n        // Construct 2 batch event processors.\n        DynamicHandler handler1 = new DynamicHandler();\n        BatchEventProcessor<StubEvent> processor1 =\n                new BatchEventProcessorBuilder().build(ringBuffer, ringBuffer.newBarrier(), handler1);\n\n        DynamicHandler handler2 = new DynamicHandler();\n        BatchEventProcessor<StubEvent> processor2 =\n                new BatchEventProcessorBuilder().build(ringBuffer, ringBuffer.newBarrier(processor1.getSequence()), handler2);\n\n        // Dynamically add both sequences to the ring buffer\n        ringBuffer.addGatingSequences(processor1.getSequence(), processor2.getSequence());\n\n        // Start the new batch processors.\n        executor.execute(processor1);\n        executor.execute(processor2);\n\n        // Remove a processor.\n\n        // Stop the processor\n        processor2.halt();\n        // Wait for shutdown the complete\n        handler2.awaitShutdown();\n        // Remove the gating sequence from the ring buffer\n        ringBuffer.removeGatingSequence(processor2.getSequence());\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/EarlyReleaseHandler.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.examples.support.LongEvent;\n\n@SuppressWarnings(\"unused\")\n// tag::example[]\npublic class EarlyReleaseHandler implements EventHandler<LongEvent>\n{\n    private Sequence sequenceCallback;\n    private int batchRemaining = 20;\n\n    @Override\n    public void setSequenceCallback(final Sequence sequenceCallback)\n    {\n        this.sequenceCallback = sequenceCallback;\n    }\n\n    @Override\n    public void onEvent(final LongEvent event, final long sequence, final boolean endOfBatch)\n    {\n        processEvent(event);\n\n        boolean logicalChunkOfWorkComplete = isLogicalChunkOfWorkComplete();\n        if (logicalChunkOfWorkComplete)\n        {\n            sequenceCallback.set(sequence);\n        }\n\n        batchRemaining = logicalChunkOfWorkComplete || endOfBatch ? 20 : batchRemaining;\n    }\n\n    private boolean isLogicalChunkOfWorkComplete()\n    {\n        // Ret true or false based on whatever criteria is required for the smaller\n        // chunk.  If this is doing I/O, it may be after flushing/syncing to disk\n        // or at the end of DB batch+commit.\n        // Or it could simply be working off a smaller batch size.\n\n        return --batchRemaining == -1;\n    }\n\n    private void processEvent(final LongEvent event)\n    {\n        // Do processing\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/HandleExceptionOnTranslate.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.EventTranslator;\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.examples.support.LongEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\npublic class HandleExceptionOnTranslate\n{\n    private static final int NO_VALUE_SPECIFIED = -1;\n\n    private static class MyHandler implements EventHandler<LongEvent>\n    {\n\n        @Override\n        public void onEvent(final LongEvent event, final long sequence, final boolean endOfBatch)\n        {\n            if (event.get() == NO_VALUE_SPECIFIED)\n            {\n                System.out.printf(\"Discarded%n\");\n            }\n            else\n            {\n                System.out.printf(\"Processed: %s%n\", event.get() == sequence);\n            }\n        }\n    }\n\n    public static void main(final String[] args) throws InterruptedException\n    {\n        Disruptor<LongEvent> disruptor = new Disruptor<>(LongEvent.FACTORY, 1024, DaemonThreadFactory.INSTANCE);\n\n        disruptor.handleEventsWith(new MyHandler());\n\n        disruptor.start();\n\n        EventTranslator<LongEvent> t = (event, sequence) ->\n        {\n            event.set(NO_VALUE_SPECIFIED);\n\n            if (sequence % 3 == 0)\n            {\n                throw new RuntimeException(\"Skipping\");\n            }\n\n            event.set(sequence);\n        };\n\n        for (int i = 0; i < 10; i++)\n        {\n            try\n            {\n                disruptor.publishEvent(t);\n            }\n            catch (RuntimeException e)\n            {\n                // Skipping\n            }\n        }\n\n        Thread.sleep(5000);\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/KeyedBatching.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.EventHandler;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class KeyedBatching implements EventHandler<KeyedBatching.KeyedEvent>\n{\n    private static final int MAX_BATCH_SIZE = 100;\n    private final List<Object> batch = new ArrayList<>();\n    private long key = 0;\n\n    @Override\n    public void onEvent(final KeyedEvent event, final long sequence, final boolean endOfBatch)\n    {\n        if (!batch.isEmpty() && event.key != key)\n        {\n            processBatch(batch);\n        }\n\n        batch.add(event.data);\n        key = event.key;\n\n        if (endOfBatch || batch.size() >= MAX_BATCH_SIZE)\n        {\n            processBatch(batch);\n        }\n    }\n\n    private void processBatch(final List<Object> batch)\n    {\n        // do work.\n        batch.clear();\n    }\n\n    public static class KeyedEvent\n    {\n        long key;\n        Object data;\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/MultiProducerWithTranslator.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.BlockingWaitStrategy;\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.EventTranslatorThreeArg;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.dsl.ProducerType;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\npublic class MultiProducerWithTranslator\n{\n    private static class IMessage\n    {\n    }\n\n    private static class ITransportable\n    {\n    }\n\n    private static class ObjectBox\n    {\n        IMessage message;\n        ITransportable transportable;\n        String string;\n\n        private static final EventFactory<ObjectBox> FACTORY = ObjectBox::new;\n\n        public void setMessage(final IMessage arg0)\n        {\n            message = arg0;\n        }\n\n        public void setTransportable(final ITransportable arg1)\n        {\n            transportable = arg1;\n        }\n\n        public void setStreamName(final String arg2)\n        {\n            string = arg2;\n        }\n    }\n\n    public static class Publisher implements EventTranslatorThreeArg<ObjectBox, IMessage, ITransportable, String>\n    {\n        @Override\n        public void translateTo(final ObjectBox event, final long sequence, final IMessage arg0, final ITransportable arg1, final String arg2)\n        {\n            event.setMessage(arg0);\n            event.setTransportable(arg1);\n            event.setStreamName(arg2);\n        }\n    }\n\n    public static class Consumer implements EventHandler<ObjectBox>\n    {\n        @Override\n        public void onEvent(final ObjectBox event, final long sequence, final boolean endOfBatch)\n        {\n\n        }\n    }\n\n    static final int RING_SIZE = 1024;\n\n    public static void main(final String[] args) throws InterruptedException\n    {\n        Disruptor<ObjectBox> disruptor = new Disruptor<>(\n                ObjectBox.FACTORY, RING_SIZE, DaemonThreadFactory.INSTANCE, ProducerType.MULTI,\n                new BlockingWaitStrategy());\n        disruptor.handleEventsWith(new Consumer()).then(new Consumer());\n        final RingBuffer<ObjectBox> ringBuffer = disruptor.getRingBuffer();\n        Publisher p = new Publisher();\n        IMessage message = new IMessage();\n        ITransportable transportable = new ITransportable();\n        String streamName = \"com.lmax.wibble\";\n        System.out.println(\"publishing \" + RING_SIZE + \" messages\");\n        for (int i = 0; i < RING_SIZE; i++)\n        {\n            ringBuffer.publishEvent(p, message, transportable, streamName);\n            Thread.sleep(10);\n        }\n        System.out.println(\"start disruptor\");\n        disruptor.start();\n        System.out.println(\"continue publishing\");\n        while (true)\n        {\n            ringBuffer.publishEvent(p, message, transportable, streamName);\n            Thread.sleep(10);\n        }\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/NamedEventHandler.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.EventHandler;\n\npublic class NamedEventHandler<T> implements EventHandler<T>\n{\n    private String oldName;\n    private final String name;\n\n    public NamedEventHandler(final String name)\n    {\n        this.name = name;\n    }\n\n    @Override\n    public void onEvent(final T event, final long sequence, final boolean endOfBatch)\n    {\n    }\n\n    @Override\n    public void onStart()\n    {\n        final Thread currentThread = Thread.currentThread();\n        oldName = currentThread.getName();\n        currentThread.setName(name);\n    }\n\n    @Override\n    public void onShutdown()\n    {\n        Thread.currentThread().setName(oldName);\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/Pipeliner.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\npublic class Pipeliner\n{\n    public static void main(final String[] args)\n    {\n        Disruptor<PipelinerEvent> disruptor = new Disruptor<>(\n                PipelinerEvent.FACTORY, 1024, DaemonThreadFactory.INSTANCE);\n\n        disruptor.handleEventsWith(\n            new ParallelHandler(0, 3),\n            new ParallelHandler(1, 3),\n            new ParallelHandler(2, 3)\n        ).then(new JoiningHandler());\n\n        RingBuffer<PipelinerEvent> ringBuffer = disruptor.start();\n\n        for (int i = 0; i < 1000; i++)\n        {\n            long next = ringBuffer.next();\n            try\n            {\n                PipelinerEvent pipelinerEvent = ringBuffer.get(next);\n                pipelinerEvent.input = i;\n            }\n            finally\n            {\n                ringBuffer.publish(next);\n            }\n        }\n    }\n\n    private static class ParallelHandler implements EventHandler<PipelinerEvent>\n    {\n        private final int ordinal;\n        private final int totalHandlers;\n\n        ParallelHandler(final int ordinal, final int totalHandlers)\n        {\n            this.ordinal = ordinal;\n            this.totalHandlers = totalHandlers;\n        }\n\n        @Override\n        public void onEvent(final PipelinerEvent event, final long sequence, final boolean endOfBatch)\n        {\n            if (sequence % totalHandlers == ordinal)\n            {\n                event.result = Long.toString(event.input);\n            }\n        }\n    }\n\n    private static class JoiningHandler implements EventHandler<PipelinerEvent>\n    {\n        private long lastEvent = -1;\n\n        @Override\n        public void onEvent(final PipelinerEvent event, final long sequence, final boolean endOfBatch)\n        {\n            if (event.input != lastEvent + 1 || event.result == null)\n            {\n                System.out.println(\"Error: \" + event);\n            }\n\n            lastEvent = event.input;\n            event.result = null;\n        }\n    }\n\n    private static class PipelinerEvent\n    {\n        long input;\n        Object result;\n\n        private static final EventFactory<PipelinerEvent> FACTORY = PipelinerEvent::new;\n\n        @Override\n        public String toString()\n        {\n            return \"PipelinerEvent{\" +\n                \"input=\" + input +\n                \", result=\" + result +\n                '}';\n        }\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/PullWithBatchedPoller.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventPoller;\nimport com.lmax.disruptor.RingBuffer;\n\n/**\n * Alternative usage of EventPoller, here we wrap it around BatchedEventPoller\n * to achieve Disruptor's batching. this speeds up the polling feature\n */\npublic class PullWithBatchedPoller\n{\n    public static void main(final String[] args) throws Exception\n    {\n        int batchSize = 40;\n        RingBuffer<BatchedPoller.DataEvent<Object>> ringBuffer =\n                RingBuffer.createMultiProducer(BatchedPoller.DataEvent.factory(), 1024);\n\n        BatchedPoller<Object> poller = new BatchedPoller<>(ringBuffer, batchSize);\n\n        Object value = poller.poll();\n\n        // Value could be null if no events are available.\n        if (null != value)\n        {\n            // Process value.\n        }\n    }\n\n    static class BatchedPoller<T>\n    {\n        private final EventPoller<DataEvent<T>> poller;\n        private final BatchedData<T> polledData;\n\n        BatchedPoller(final RingBuffer<DataEvent<T>> ringBuffer, final int batchSize)\n        {\n            this.poller = ringBuffer.newPoller();\n            ringBuffer.addGatingSequences(poller.getSequence());\n            this.polledData = new BatchedData<>(batchSize);\n        }\n\n        public T poll() throws Exception\n        {\n            if (polledData.getMsgCount() > 0)\n            {\n                return polledData.pollMessage(); // we just fetch from our local\n            }\n\n            loadNextValues(poller, polledData); // we try to load from the ring\n            return polledData.getMsgCount() > 0 ? polledData.pollMessage() : null;\n        }\n\n        private EventPoller.PollState loadNextValues(final EventPoller<DataEvent<T>> poller, final BatchedData<T> batch)\n                throws Exception\n        {\n            return poller.poll((event, sequence, endOfBatch) ->\n            {\n                T item = event.copyOfData();\n                return item != null ? batch.addDataItem(item) : false;\n            });\n        }\n\n        public static class DataEvent<T>\n        {\n            T data;\n\n            public static <T> EventFactory<DataEvent<T>> factory()\n            {\n                return DataEvent::new;\n            }\n\n            public T copyOfData()\n            {\n                // Copy the data out here. In this case we have a single reference\n                // object, so the pass by\n                // reference is sufficient. But if we were reusing a byte array,\n                // then we\n                // would need to copy\n                // the actual contents.\n                return data;\n            }\n\n            void set(final T d)\n            {\n                data = d;\n            }\n        }\n\n        private static class BatchedData<T>\n        {\n            private int msgHighBound;\n            private final int capacity;\n            private final T[] data;\n            private int cursor;\n\n            @SuppressWarnings(\"unchecked\")\n            BatchedData(final int size)\n            {\n                this.capacity = size;\n                data = (T[]) new Object[this.capacity];\n            }\n\n            private void clearCount()\n            {\n                msgHighBound = 0;\n                cursor = 0;\n            }\n\n            public int getMsgCount()\n            {\n                return msgHighBound - cursor;\n            }\n\n            public boolean addDataItem(final T item) throws IndexOutOfBoundsException\n            {\n                if (msgHighBound >= capacity)\n                {\n                    throw new IndexOutOfBoundsException(\"Attempting to add item to full batch\");\n                }\n\n                data[msgHighBound++] = item;\n                return msgHighBound < capacity;\n            }\n\n            public T pollMessage()\n            {\n                T rtVal = null;\n                if (cursor < msgHighBound)\n                {\n                    rtVal = data[cursor++];\n                }\n                if (cursor > 0 && cursor >= msgHighBound)\n                {\n                    clearCount();\n                }\n                return rtVal;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/PullWithPoller.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventPoller;\nimport com.lmax.disruptor.RingBuffer;\n\npublic class PullWithPoller\n{\n    public static class DataEvent<T>\n    {\n        T data;\n\n        public static <T> EventFactory<DataEvent<T>> factory()\n        {\n            return DataEvent::new;\n        }\n\n        public T copyOfData()\n        {\n            // Copy the data out here.  In this case we have a single reference object, so the pass by\n            // reference is sufficient.  But if we were reusing a byte array, then we would need to copy\n            // the actual contents.\n            return data;\n        }\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        RingBuffer<DataEvent<Object>> ringBuffer = RingBuffer.createMultiProducer(DataEvent.factory(), 1024);\n\n        final EventPoller<DataEvent<Object>> poller = ringBuffer.newPoller();\n\n        Object value = getNextValue(poller);\n\n        // Value could be null if no events are available.\n        if (null != value)\n        {\n            // Process value.\n        }\n    }\n\n    private static Object getNextValue(final EventPoller<DataEvent<Object>> poller) throws Exception\n    {\n        final Object[] out = new Object[1];\n\n        poller.poll(\n                (event, sequence, endOfBatch) ->\n                {\n                    out[0] = event.copyOfData();\n\n                    // Return false so that only one event is processed at a time.\n                    return false;\n                });\n\n        return out[0];\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/SequentialThreeConsumers.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\npublic class SequentialThreeConsumers\n{\n    private static class MyEvent\n    {\n        private Object a;\n        private Object b;\n        private Object c;\n        private Object d;\n    }\n\n    public static void main(final String[] args)\n    {\n        Disruptor<MyEvent> disruptor = new Disruptor<>(MyEvent::new, 1024, DaemonThreadFactory.INSTANCE);\n\n        disruptor.handleEventsWith((event, sequence, endOfBatch) -> event.b = event.a)\n                .then((event, sequence, endOfBatch) -> event.c = event.b)\n                .then((event, sequence, endOfBatch) -> event.d = event.c);\n\n        disruptor.start();\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/ShutdownOnError.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.ExceptionHandler;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class ShutdownOnError\n{\n    private static class Event\n    {\n        public long value;\n\n        public static final EventFactory<Event> FACTORY = Event::new;\n    }\n\n    private static class Handler implements EventHandler<Event>\n    {\n        @Override\n        public void onEvent(final Event event, final long sequence, final boolean endOfBatch)\n        {\n            // do work, if a failure occurs throw exception.\n        }\n    }\n\n    private static final class ErrorHandler implements ExceptionHandler<Event>\n    {\n        private final AtomicBoolean running;\n\n        private ErrorHandler(final AtomicBoolean running)\n        {\n            this.running = running;\n        }\n\n        @Override\n        public void handleEventException(final Throwable ex, final long sequence, final Event event)\n        {\n            if (execeptionIsFatal(ex))\n            {\n                throw new RuntimeException(ex);\n            }\n        }\n\n        private boolean execeptionIsFatal(final Throwable ex)\n        {\n            // Do what is appropriate here.\n            return true;\n        }\n\n        @Override\n        public void handleOnStartException(final Throwable ex)\n        {\n\n        }\n\n        @Override\n        public void handleOnShutdownException(final Throwable ex)\n        {\n\n        }\n    }\n\n    public static void main(final String[] args)\n    {\n        Disruptor<Event> disruptor = new Disruptor<>(Event.FACTORY, 1024, DaemonThreadFactory.INSTANCE);\n\n        AtomicBoolean running = new AtomicBoolean(true);\n\n        ErrorHandler errorHandler = new ErrorHandler(running);\n\n        final Handler handler = new Handler();\n        disruptor.handleEventsWith(handler);\n        disruptor.handleExceptionsFor(handler).with(errorHandler);\n\n        simplePublish(disruptor, running);\n    }\n\n    private static void simplePublish(final Disruptor<Event> disruptor, final AtomicBoolean running)\n    {\n        while (running.get())\n        {\n            disruptor.publishEvent((event, sequence) -> event.value = sequence);\n        }\n    }\n\n    private static void smarterPublish(final Disruptor<Event> disruptor, final AtomicBoolean running)\n    {\n        final RingBuffer<Event> ringBuffer = disruptor.getRingBuffer();\n\n        boolean publishOk;\n        do\n        {\n            publishOk = ringBuffer.tryPublishEvent((event, sequence) -> event.value = sequence);\n        }\n        while (publishOk && running.get());\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/ThreeToOneDisruptor.java",
    "content": "package com.lmax.disruptor.examples;\n\n\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\npublic class ThreeToOneDisruptor\n{\n    public static class DataEvent\n    {\n        Object input;\n        Object[] output;\n\n        public DataEvent(final int size)\n        {\n            output = new Object[size];\n        }\n\n        public static final EventFactory<DataEvent> FACTORY = () -> new DataEvent(3);\n    }\n\n    public static class TransformingHandler implements EventHandler<DataEvent>\n    {\n        private final int outputIndex;\n\n        public TransformingHandler(final int outputIndex)\n        {\n            this.outputIndex = outputIndex;\n        }\n\n        @Override\n        public void onEvent(final DataEvent event, final long sequence, final boolean endOfBatch)\n        {\n            // Do Stuff.\n            event.output[outputIndex] = doSomething(event.input);\n        }\n\n        private Object doSomething(final Object input)\n        {\n            // Do required transformation here....\n            return input;\n        }\n    }\n\n    public static class CollatingHandler implements EventHandler<DataEvent>\n    {\n        @Override\n        public void onEvent(final DataEvent event, final long sequence, final boolean endOfBatch)\n        {\n            collate(event.output);\n        }\n\n        private void collate(final Object[] output)\n        {\n            // Do required collation here....\n        }\n    }\n\n    public static void main(final String[] args)\n    {\n        Disruptor<DataEvent> disruptor = new Disruptor<>(\n                DataEvent.FACTORY, 1024, DaemonThreadFactory.INSTANCE);\n\n        TransformingHandler handler1 = new TransformingHandler(0);\n        TransformingHandler handler2 = new TransformingHandler(1);\n        TransformingHandler handler3 = new TransformingHandler(2);\n        CollatingHandler collator = new CollatingHandler();\n\n        disruptor.handleEventsWith(handler1, handler2, handler3).then(collator);\n\n        disruptor.start();\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/WaitForProcessing.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.EventTranslator;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.examples.support.LongEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\npublic class WaitForProcessing\n{\n    public static class Consumer implements EventHandler<LongEvent>\n    {\n        @Override\n        public void onEvent(final LongEvent event, final long sequence, final boolean endOfBatch)\n        {\n\n        }\n    }\n\n    public static void main(final String[] args)\n    {\n        final Disruptor<LongEvent> disruptor = new Disruptor<>(\n            LongEvent.FACTORY, 1024, DaemonThreadFactory.INSTANCE);\n\n        Consumer firstConsumer = new Consumer();\n        Consumer lastConsumer = new Consumer();\n        disruptor.handleEventsWith(firstConsumer).then(lastConsumer);\n        final RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();\n\n        EventTranslator<LongEvent> translator = (event, sequence) -> event.set(sequence - 4);\n\n        ringBuffer.tryPublishEvent(translator);\n\n        waitForSpecificConsumer(disruptor, lastConsumer, ringBuffer);\n        waitForRingBufferToBeIdle(ringBuffer);\n    }\n\n    @SuppressWarnings(\"StatementWithEmptyBody\")\n    private static void waitForRingBufferToBeIdle(final RingBuffer<LongEvent> ringBuffer)\n    {\n        while (ringBuffer.getBufferSize() - ringBuffer.remainingCapacity() != 0)\n        {\n            // Wait for priocessing...\n        }\n    }\n\n    private static void waitForSpecificConsumer(\n        final Disruptor<LongEvent> disruptor,\n        final Consumer lastConsumer,\n        final RingBuffer<LongEvent> ringBuffer)\n    {\n        long lastPublishedValue;\n        long sequenceValueFor;\n        do\n        {\n            lastPublishedValue = ringBuffer.getCursor();\n            sequenceValueFor = disruptor.getSequenceValueFor(lastConsumer);\n        }\n        while (sequenceValueFor < lastPublishedValue);\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/WaitForShutdown.java",
    "content": "package com.lmax.disruptor.examples;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.TimeoutException;\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.examples.support.LongEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\npublic class WaitForShutdown\n{\n    private static volatile int value = 0;\n\n    private static class Handler implements EventHandler<LongEvent>\n    {\n        private final CountDownLatch latch;\n\n        Handler(final CountDownLatch latch)\n        {\n            this.latch = latch;\n        }\n\n        @Override\n        public void onStart()\n        {\n        }\n\n        @Override\n        public void onShutdown()\n        {\n            latch.countDown();\n        }\n\n        @Override\n        public void onEvent(final LongEvent event, final long sequence, final boolean endOfBatch)\n        {\n            value = 1;\n        }\n    }\n\n    public static void main(final String[] args) throws TimeoutException, InterruptedException\n    {\n        Disruptor<LongEvent> disruptor = new Disruptor<>(\n                LongEvent.FACTORY, 16, DaemonThreadFactory.INSTANCE\n        );\n\n        CountDownLatch shutdownLatch = new CountDownLatch(2);\n\n        disruptor.handleEventsWith(new Handler(shutdownLatch)).then(new Handler(shutdownLatch));\n        disruptor.start();\n\n        long next = disruptor.getRingBuffer().next();\n        disruptor.getRingBuffer().get(next).set(next);\n        disruptor.getRingBuffer().publish(next);\n\n        disruptor.shutdown(10, TimeUnit.SECONDS);\n\n        shutdownLatch.await();\n\n        System.out.println(value);\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/longevent/LongEvent.java",
    "content": "package com.lmax.disruptor.examples.longevent;\n\n// tag::example[]\npublic class LongEvent\n{\n    private long value;\n\n    public void set(long value)\n    {\n        this.value = value;\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"LongEvent{\" + \"value=\" + value + '}';\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/longevent/LongEventFactory.java",
    "content": "package com.lmax.disruptor.examples.longevent;\n\nimport com.lmax.disruptor.EventFactory;\n\n// tag::example[]\npublic class LongEventFactory implements EventFactory<LongEvent>\n{\n    @Override\n    public LongEvent newInstance()\n    {\n        return new LongEvent();\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/longevent/LongEventHandler.java",
    "content": "package com.lmax.disruptor.examples.longevent;\n\nimport com.lmax.disruptor.EventHandler;\n\n// tag::example[]\npublic class LongEventHandler implements EventHandler<LongEvent>\n{\n    @Override\n    public void onEvent(LongEvent event, long sequence, boolean endOfBatch)\n    {\n        System.out.println(\"Event: \" + event);\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/longevent/LongEventProducer.java",
    "content": "package com.lmax.disruptor.examples.longevent;\n\n// tag::example[]\n\nimport com.lmax.disruptor.EventTranslatorOneArg;\nimport com.lmax.disruptor.RingBuffer;\n\nimport java.nio.ByteBuffer;\n\npublic class LongEventProducer\n{\n    private final RingBuffer<LongEvent> ringBuffer;\n\n    public LongEventProducer(RingBuffer<LongEvent> ringBuffer)\n    {\n        this.ringBuffer = ringBuffer;\n    }\n\n    private static final EventTranslatorOneArg<LongEvent, ByteBuffer> TRANSLATOR =\n        new EventTranslatorOneArg<LongEvent, ByteBuffer>()\n        {\n            @Override\n            public void translateTo(LongEvent event, long sequence, ByteBuffer bb)\n            {\n                event.set(bb.getLong(0));\n            }\n        };\n\n    public void onData(ByteBuffer bb)\n    {\n        ringBuffer.publishEvent(TRANSLATOR, bb);\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/longevent/LongEventProducerWithTranslator.java",
    "content": "package com.lmax.disruptor.examples.longevent;\n\n// tag::example[]\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.EventTranslatorOneArg;\n\nimport java.nio.ByteBuffer;\n\npublic class LongEventProducerWithTranslator\n{\n    private final RingBuffer<LongEvent> ringBuffer;\n\n    public LongEventProducerWithTranslator(RingBuffer<LongEvent> ringBuffer)\n    {\n        this.ringBuffer = ringBuffer;\n    }\n\n    private static final EventTranslatorOneArg<LongEvent, ByteBuffer> TRANSLATOR =\n        new EventTranslatorOneArg<LongEvent, ByteBuffer>()\n        {\n            @Override\n            public void translateTo(LongEvent event, long sequence, ByteBuffer bb)\n            {\n                event.set(bb.getLong(0));\n            }\n        };\n\n    public void onData(ByteBuffer bb)\n    {\n        ringBuffer.publishEvent(TRANSLATOR, bb);\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/longevent/lambdas/LongEventMain.java",
    "content": "package com.lmax.disruptor.examples.longevent.lambdas;\n\n// tag::example[]\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.examples.longevent.LongEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport java.nio.ByteBuffer;\n\npublic class LongEventMain\n{\n    public static void main(String[] args) throws Exception\n    {\n        int bufferSize = 1024; // <1>\n\n        Disruptor<LongEvent> disruptor = // <2>\n                new Disruptor<>(LongEvent::new, bufferSize, DaemonThreadFactory.INSTANCE);\n\n        disruptor.handleEventsWith((event, sequence, endOfBatch) ->\n                System.out.println(\"Event: \" + event)); // <3>\n        disruptor.start(); // <4>\n\n\n        RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer(); // <5>\n        ByteBuffer bb = ByteBuffer.allocate(8);\n        for (long l = 0; true; l++)\n        {\n            bb.putLong(0, l);\n            ringBuffer.publishEvent((event, sequence, buffer) -> event.set(buffer.getLong(0)), bb);\n            Thread.sleep(1000);\n        }\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/longevent/legacy/LongEventMain.java",
    "content": "package com.lmax.disruptor.examples.longevent.legacy;\n\n// tag::example[]\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.examples.longevent.LongEvent;\nimport com.lmax.disruptor.examples.longevent.LongEventFactory;\nimport com.lmax.disruptor.examples.longevent.LongEventHandler;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.nio.ByteBuffer;\n\npublic class LongEventMain\n{\n    public static void main(String[] args) throws Exception\n    {\n        LongEventFactory factory = new LongEventFactory();\n\n        int bufferSize = 1024;\n        Disruptor<LongEvent> disruptor =\n                new Disruptor<>(factory, bufferSize, DaemonThreadFactory.INSTANCE);\n        disruptor.handleEventsWith(new LongEventHandler());\n        disruptor.start();\n\n        RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();\n        LongEventProducer producer = new LongEventProducer(ringBuffer);\n        ByteBuffer bb = ByteBuffer.allocate(8);\n        for (long l = 0; true; l++)\n        {\n            bb.putLong(0, l);\n            producer.onData(bb);\n            Thread.sleep(1000);\n        }\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/longevent/legacy/LongEventProducer.java",
    "content": "package com.lmax.disruptor.examples.longevent.legacy;\n\n// tag::example[]\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.examples.longevent.LongEvent;\n\nimport java.nio.ByteBuffer;\n\npublic class LongEventProducer\n{\n    private final RingBuffer<LongEvent> ringBuffer;\n\n    public LongEventProducer(RingBuffer<LongEvent> ringBuffer)\n    {\n        this.ringBuffer = ringBuffer;\n    }\n\n    public void onData(ByteBuffer bb)\n    {\n        long sequence = ringBuffer.next(); // <1>\n        try\n        {\n            LongEvent event = ringBuffer.get(sequence); // <2>\n            event.set(bb.getLong(0));  // <3>\n        }\n        finally\n        {\n            ringBuffer.publish(sequence);\n        }\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/longevent/methodrefs/LongEventMain.java",
    "content": "package com.lmax.disruptor.examples.longevent.methodrefs;\n\n// tag::example[]\n\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.examples.longevent.LongEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.nio.ByteBuffer;\n\npublic class LongEventMain\n{\n    public static void handleEvent(LongEvent event, long sequence, boolean endOfBatch)\n    {\n        System.out.println(event);\n    }\n\n    public static void translate(LongEvent event, long sequence, ByteBuffer buffer)\n    {\n        event.set(buffer.getLong(0));\n    }\n\n    public static void main(String[] args) throws Exception\n    {\n        int bufferSize = 1024;\n\n        Disruptor<LongEvent> disruptor =\n                new Disruptor<>(LongEvent::new, bufferSize, DaemonThreadFactory.INSTANCE);\n        disruptor.handleEventsWith(LongEventMain::handleEvent);\n        disruptor.start();\n\n        RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();\n        ByteBuffer bb = ByteBuffer.allocate(8);\n        for (long l = 0; true; l++)\n        {\n            bb.putLong(0, l);\n            ringBuffer.publishEvent(LongEventMain::translate, bb);\n            Thread.sleep(1000);\n        }\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/objectevent/ClearingEventHandler.java",
    "content": "package com.lmax.disruptor.examples.objectevent;\n\n// tag::example[]\nimport com.lmax.disruptor.EventHandler;\n\npublic class ClearingEventHandler<T> implements EventHandler<ObjectEvent<T>>\n{\n    @Override\n    public void onEvent(ObjectEvent<T> event, long sequence, boolean endOfBatch)\n    {\n        event.clear(); // <1>\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/objectevent/Main.java",
    "content": "package com.lmax.disruptor.examples.objectevent;\n\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\n@SuppressWarnings(\"unchecked\")\npublic class Main\n{\n    private static final int BUFFER_SIZE = 1024;\n\n    // tag::example[]\n    public static void main(String[] args)\n    {\n        Disruptor<ObjectEvent<String>> disruptor = new Disruptor<>(\n                () -> new ObjectEvent<>(), BUFFER_SIZE, DaemonThreadFactory.INSTANCE);\n\n        disruptor\n                .handleEventsWith(new ProcessingEventHandler())\n                .then(new ClearingEventHandler());\n    }\n    // end::example[]\n\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/objectevent/ObjectEvent.java",
    "content": "package com.lmax.disruptor.examples.objectevent;\n\n// tag::example[]\nclass ObjectEvent<T>\n{\n    T val;\n\n    void clear()\n    {\n        val = null;\n    }\n}\n// end::example[]"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/objectevent/ProcessingEventHandler.java",
    "content": "package com.lmax.disruptor.examples.objectevent;\n\nimport com.lmax.disruptor.EventHandler;\n\npublic class ProcessingEventHandler<T> implements EventHandler<ObjectEvent<T>>\n{\n    @Override\n    public void onEvent(ObjectEvent<T> event, long sequence, boolean endOfBatch) throws Exception\n    {\n    }\n}\n"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/support/LongEvent.java",
    "content": "package com.lmax.disruptor.examples.support;\n\nimport com.lmax.disruptor.EventFactory;\n\npublic class LongEvent\n{\n    public static final EventFactory<LongEvent> FACTORY = LongEvent::new;\n\n    private long value;\n\n    public void set(final long value)\n    {\n        this.value = value;\n    }\n\n    public long get()\n    {\n        return value;\n    }\n}"
  },
  {
    "path": "src/examples/java/com/lmax/disruptor/examples/support/StubEvent.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.examples.support;\n\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventTranslatorTwoArg;\n\npublic final class StubEvent\n{\n    private int value;\n    private String testString;\n    public static final EventTranslatorTwoArg<StubEvent, Integer, String> TRANSLATOR = (event, sequence, arg0, arg1) ->\n            {\n                event.setValue(arg0);\n                event.setTestString(arg1);\n            };\n\n    public StubEvent(final int i)\n    {\n        this.value = i;\n    }\n\n    public void copy(final StubEvent event)\n    {\n        value = event.value;\n    }\n\n    public int getValue()\n    {\n        return value;\n    }\n\n    public void setValue(final int value)\n    {\n        this.value = value;\n    }\n\n    public String getTestString()\n    {\n        return testString;\n    }\n\n    public void setTestString(final String testString)\n    {\n        this.testString = testString;\n    }\n\n    public static final EventFactory<StubEvent> EVENT_FACTORY = () -> new StubEvent(-1);\n\n    @Override\n    public boolean equals(final Object o)\n    {\n        if (this == o)\n        {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass())\n        {\n            return false;\n        }\n\n        final StubEvent stubEvent = (StubEvent) o;\n\n        if (value != stubEvent.value)\n        {\n            return false;\n        }\n        return testString != null ? testString.equals(stubEvent.testString) : stubEvent.testString == null;\n    }\n\n    @Override\n    public int hashCode()\n    {\n        int result = value;\n        result = 31 * result + (testString != null ? testString.hashCode() : 0);\n        return result;\n    }\n}\n"
  },
  {
    "path": "src/jcstress/java/com/lmax/disruptor/LoggerInitializationStress.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.dsl.ProducerType;\nimport com.lmax.disruptor.util.UnsafeAccess;\nimport org.openjdk.jcstress.annotations.Actor;\nimport org.openjdk.jcstress.annotations.JCStressTest;\nimport org.openjdk.jcstress.annotations.Mode;\nimport org.openjdk.jcstress.annotations.Outcome;\nimport org.openjdk.jcstress.annotations.Signal;\nimport sun.misc.Unsafe;\n\nimport java.lang.reflect.Field;\nimport java.util.concurrent.Executors;\nimport java.util.logging.LogManager;\n\nimport static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE;\nimport static org.openjdk.jcstress.annotations.Expect.FORBIDDEN;\n\n/**\n * Validate that creating a {@link Disruptor} instance with a custom {@link ExceptionHandler} does not\n * initialize the logging framework. Using JCStress is a stretch, we're not validating a race condition,\n * rather that the logging framework is not started. This type of test doesn't work well in unit tests\n * because it requires JVM isolation, and any interactions with a logger invalidate the test.\n */\n@JCStressTest(Mode.Termination)\n@Outcome(id = \"TERMINATED\", expect = ACCEPTABLE, desc = \"Logger has not been initialized\")\n@Outcome(\n        id = {\"STALE\", \"ERROR\"},\n        expect = FORBIDDEN,\n        desc = \"Logger has been initialized. This has the potential to cause \" +\n                \"deadlocks when disruptor is used within logging frameworks\")\npublic class LoggerInitializationStress\n{\n    private static volatile boolean logManagerInitialized;\n    private static volatile boolean disruptorInitialized;\n    static\n    {\n        System.setProperty(\"java.util.logging.manager\", DisruptorLogManager.class.getCanonicalName());\n    }\n\n    @Actor\n    public void actor() throws Exception\n    {\n        // Wait for a the Disruptor instance to be initialized\n        while (!disruptorInitialized)\n        {\n        }\n        // Validate state\n        if (logManagerInitialized)\n        {\n            throw new RuntimeException(\"Expected the LogManager to be uninitialized\");\n        }\n        // Use Unsafe to determine if the LogManager has been initialized.\n        // Accessing the LogManager normally using LogManager.getLogManager\n        // results in initialization which modifies static state and prevents\n        // subsequent runs from executing successfully.\n        Field managerField = LogManager.class.getDeclaredField(\"manager\");\n        Unsafe unsafe = UnsafeAccess.getUnsafe();\n        Object managerBase = unsafe.staticFieldBase(managerField);\n        long managerOffset = unsafe.staticFieldOffset(managerField);\n        Object logManager = unsafe.getObject(managerBase, managerOffset);\n        if (logManager != null)\n        {\n            throw new RuntimeException(\"Unexpected LogManager: \" + logManager);\n        }\n    }\n\n    @Signal\n    public void signal()\n    {\n        final Disruptor disruptor = new Disruptor<>(\n                SimpleEvent::new,\n                128,\n                Executors.defaultThreadFactory(),\n                ProducerType.MULTI,\n                new BlockingWaitStrategy());\n        disruptor.setDefaultExceptionHandler(SimpleEventExceptionHandler.INSTANCE);\n        disruptor.handleEventsWith(SimpleEventHandler.INSTANCE);\n        disruptor.start();\n        disruptor.halt();\n        disruptorInitialized = true;\n    }\n\n    public static final class DisruptorLogManager extends LogManager\n    {\n        static\n        {\n            logManagerInitialized = true;\n        }\n    }\n\n    public static final class SimpleEvent\n    {\n        private long value = Long.MIN_VALUE;\n\n        public long getValue()\n        {\n            return value;\n        }\n\n        public void setValue(final long value)\n        {\n            this.value = value;\n        }\n\n        @Override\n        public String toString()\n        {\n            return \"SimpleEvent{\" +\n                    \"value=\" + value +\n                    '}';\n        }\n    }\n\n    public enum SimpleEventHandler implements EventHandler<SimpleEvent>\n    {\n        INSTANCE;\n\n        @Override\n        public void onEvent(final SimpleEvent event, final long sequence, final boolean endOfBatch)\n        {\n            // nop\n        }\n    }\n\n    public enum SimpleEventExceptionHandler implements ExceptionHandler<SimpleEvent>\n    {\n        INSTANCE;\n\n        @Override\n        public void handleEventException(final Throwable ex, final long sequence, final SimpleEvent event)\n        {\n            // nop\n        }\n\n        @Override\n        public void handleOnStartException(final Throwable ex)\n        {\n            // nop\n        }\n\n        @Override\n        public void handleOnShutdownException(final Throwable ex)\n        {\n            // nop\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/jcstress/java/com/lmax/disruptor/MultiProducerSequencerUnsafeStress.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.alternatives.MultiProducerSequencerUnsafe;\nimport org.openjdk.jcstress.annotations.Actor;\nimport org.openjdk.jcstress.annotations.JCStressTest;\nimport org.openjdk.jcstress.annotations.Outcome;\nimport org.openjdk.jcstress.annotations.State;\nimport org.openjdk.jcstress.infra.results.ZZ_Result;\n\nimport static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE;\nimport static org.openjdk.jcstress.annotations.Expect.FORBIDDEN;\n\npublic final class MultiProducerSequencerUnsafeStress\n{\n    private static Sequencer createSequencer()\n    {\n        return new MultiProducerSequencerUnsafe(64, new BlockingWaitStrategy());\n    }\n\n    @JCStressTest\n    @Outcome(id = {\"false, false\", \"true, false\", \"true, true\"}, expect = ACCEPTABLE, desc = \"Assuming ordered updates\")\n    @Outcome(id = \"false, true\", expect = FORBIDDEN, desc = \"publish(2) should not be available before publish(1)\")\n    @State\n    public static class PublishUpdatesIsAvailableLazily\n    {\n        Sequencer sequencer = createSequencer();\n\n        @Actor\n        public void actor1()\n        {\n            // The store to the underlying availableBuffer is lazily done and stores can be visible out of order\n            sequencer.publish(1);\n            sequencer.publish(2);\n        }\n\n        @Actor\n        public void actor2(final ZZ_Result r)\n        {\n            // The load in isAvailable is a full store/load barrier, so any stores from actor1 should get flushed\n            r.r2 = sequencer.isAvailable(2);\n            r.r1 = sequencer.isAvailable(1);\n        }\n    }\n\n    /**\n     * The isAvailable implementation is volatile so we should never see an update to it without seeing the update to a\n     * previously set value also.\n     *\n     * <p>If the value was not volatile there would be no ordering rules stopping it being seen updated before the\n     * other value.\n     */\n    @JCStressTest\n    @Outcome(id = \"false, false\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"true, true\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"false, true\", expect = ACCEPTABLE, desc = \"Caught in the middle: $x is visible, $y is not.\")\n    @Outcome(id = \"true, false\", expect = FORBIDDEN, desc = \"Seeing $y, but not $x!\")\n    @State\n    public static class GetVolatile\n    {\n        boolean x = false;\n        Sequencer y = createSequencer();\n\n        @Actor\n        public void actor1()\n        {\n            x = true;\n            y.publish(1);\n        }\n\n        @Actor\n        public void actor2(final ZZ_Result r)\n        {\n            r.r1 = y.isAvailable(1);\n            r.r2 = x;\n        }\n    }\n\n    /**\n     * In absence of synchronization, the order of independent reads is undefined.\n     * In our case, the read of isAvailable is volatile which mandates the writes to the same\n     * variable to be observed in a total order (that implies that _observers_ are also ordered)\n     */\n    @JCStressTest\n    @Outcome(id = \"false, false\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"true, true\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"false, true\", expect = ACCEPTABLE, desc = \"Doing first read early, not surprising.\")\n    @Outcome(id = \"true, false\", expect = FORBIDDEN, desc = \"Violates coherence.\")\n    @State\n    public static class SameVolatileRead\n    {\n        private final SameVolatileRead.Holder h1 = new SameVolatileRead.Holder();\n        private final SameVolatileRead.Holder h2 = h1;\n\n        private static class Holder\n        {\n            Sequencer sequence = createSequencer();\n        }\n\n        @Actor\n        public void actor1()\n        {\n            h1.sequence.publish(1);\n        }\n\n        @Actor\n        public void actor2(final ZZ_Result r)\n        {\n            SameVolatileRead.Holder h1 = this.h1;\n            SameVolatileRead.Holder h2 = this.h2;\n\n            r.r1 = h1.sequence.isAvailable(1);\n            r.r2 = h2.sequence.isAvailable(1);\n        }\n    }\n}\n"
  },
  {
    "path": "src/jcstress/java/com/lmax/disruptor/MultiProducerSequencerVarHandleStress.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.alternatives.MultiProducerSequencerVarHandle;\nimport org.openjdk.jcstress.annotations.Actor;\nimport org.openjdk.jcstress.annotations.JCStressTest;\nimport org.openjdk.jcstress.annotations.Outcome;\nimport org.openjdk.jcstress.annotations.State;\nimport org.openjdk.jcstress.infra.results.ZZ_Result;\n\nimport static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE;\nimport static org.openjdk.jcstress.annotations.Expect.FORBIDDEN;\n\npublic final class MultiProducerSequencerVarHandleStress\n{\n    private static Sequencer createSequencer()\n    {\n        return new MultiProducerSequencerVarHandle(64, new BlockingWaitStrategy());\n    }\n\n    @JCStressTest\n    @Outcome(id = {\"false, false\", \"true, false\", \"true, true\"}, expect = ACCEPTABLE, desc = \"Assuming ordered updates\")\n    @Outcome(id = \"false, true\", expect = FORBIDDEN, desc = \"publish(2) should not be available before publish(1)\")\n    @State\n    public static class PublishUpdatesIsAvailableLazily\n    {\n        Sequencer sequencer = createSequencer();\n\n        @Actor\n        public void actor1()\n        {\n            sequencer.publish(1);\n            sequencer.publish(2);\n        }\n\n        @Actor\n        public void actor2(final ZZ_Result r)\n        {\n            r.r2 = sequencer.isAvailable(2);\n            r.r1 = sequencer.isAvailable(1);\n        }\n    }\n\n    /**\n     * The isAvailable implementation is volatile so we should never see an update to it without seeing the update to a\n     * previously set value also.\n     *\n     * <p>If the value was not volatile there would be no ordering rules stopping it being seen updated before the\n     * other value.\n     */\n    @JCStressTest\n    @Outcome(id = \"false, false\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"true, true\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"false, true\", expect = ACCEPTABLE, desc = \"Caught in the middle: $x is visible, $y is not.\")\n    @Outcome(id = \"true, false\", expect = FORBIDDEN, desc = \"Seeing $y, but not $x!\")\n    @State\n    public static class GetVolatile\n    {\n        boolean x = false;\n        Sequencer y = createSequencer();\n\n        @Actor\n        public void actor1()\n        {\n            x = true;\n            y.publish(1);\n        }\n\n        @Actor\n        public void actor2(final ZZ_Result r)\n        {\n            r.r1 = y.isAvailable(1);\n            r.r2 = x;\n        }\n    }\n\n    /**\n     * In absence of synchronization, the order of independent reads is undefined.\n     * In our case, the read of isAvailable is volatile which mandates the writes to the same\n     * variable to be observed in a total order (that implies that _observers_ are also ordered)\n     */\n    @JCStressTest\n    @Outcome(id = \"false, false\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"true, true\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"false, true\", expect = ACCEPTABLE, desc = \"Doing first read early, not surprising.\")\n    @Outcome(id = \"true, false\", expect = FORBIDDEN, desc = \"Violates coherence.\")\n    @State\n    public static class SameVolatileRead\n    {\n        private final Holder h1 = new Holder();\n        private final Holder h2 = h1;\n\n        private static class Holder\n        {\n            Sequencer sequence = createSequencer();\n        }\n\n        @Actor\n        public void actor1()\n        {\n            h1.sequence.publish(1);\n        }\n\n        @Actor\n        public void actor2(final ZZ_Result r)\n        {\n            Holder h1 = this.h1;\n            Holder h2 = this.h2;\n\n            r.r1 = h1.sequence.isAvailable(1);\n            r.r2 = h2.sequence.isAvailable(1);\n        }\n    }\n}\n"
  },
  {
    "path": "src/jcstress/java/com/lmax/disruptor/SequenceStressUnsafe.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.alternatives.SequenceUnsafe;\nimport org.openjdk.jcstress.annotations.Actor;\nimport org.openjdk.jcstress.annotations.Arbiter;\nimport org.openjdk.jcstress.annotations.JCStressTest;\nimport org.openjdk.jcstress.annotations.Outcome;\nimport org.openjdk.jcstress.annotations.Ref;\nimport org.openjdk.jcstress.annotations.State;\nimport org.openjdk.jcstress.infra.results.JJ_Result;\nimport org.openjdk.jcstress.infra.results.J_Result;\nimport org.openjdk.jcstress.infra.results.ZZJ_Result;\n\nimport static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE;\nimport static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE_INTERESTING;\nimport static org.openjdk.jcstress.annotations.Expect.FORBIDDEN;\n\npublic class SequenceStressUnsafe\n{\n    /**\n     * `SequenceUnsafe::incrementAndGet` is atomic and should never lose an update, even with multiple threads racing.\n     */\n    @JCStressTest\n    @Outcome(id = \"1\", expect = FORBIDDEN, desc = \"One update lost.\")\n    @Outcome(id = \"2\", expect = ACCEPTABLE, desc = \"Both updates.\")\n    @State\n    public static class IncrementAndGet\n    {\n        SequenceUnsafe sequence = new SequenceUnsafe(0);\n\n        @Actor\n        public void actor1()\n        {\n            sequence.incrementAndGet();\n        }\n\n        @Actor\n        public void actor2()\n        {\n            sequence.incrementAndGet();\n        }\n\n        @Arbiter\n        public void arbiter(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * `SequenceUnsafe::compareAndSet` is atomic and should never lose an update, even with multiple threads racing.\n     */\n    @JCStressTest\n    @Outcome(id = {\"true, false, 10\", \"false, true, 20\"}, expect = ACCEPTABLE, desc = \"Either updated.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @State\n    public static class CompareAndSet\n    {\n        SequenceUnsafe sequence = new SequenceUnsafe(0);\n\n        @Actor\n        public void actor1(final ZZJ_Result r)\n        {\n            r.r1 = sequence.compareAndSet(0, 10);\n        }\n\n        @Actor\n        public void actor2(final ZZJ_Result r)\n        {\n            r.r2 = sequence.compareAndSet(0, 20);\n        }\n\n        @Arbiter\n        public void arbiter(final ZZJ_Result r)\n        {\n            r.r3 = sequence.get();\n        }\n    }\n\n    /**\n     * `SequenceUnsafe::addAndGet` is atomic and should never lose an update, even with multiple threads racing.\n     */\n    @JCStressTest\n    @Outcome(id = \"10\", expect = FORBIDDEN, desc = \"One update lost.\")\n    @Outcome(id = \"20\", expect = FORBIDDEN, desc = \"One update lost.\")\n    @Outcome(id = \"30\", expect = ACCEPTABLE, desc = \"Both updates.\")\n    @State\n    public static class AddAndGet\n    {\n        SequenceUnsafe sequence = new SequenceUnsafe(0);\n\n        @Actor\n        public void actor1()\n        {\n            sequence.addAndGet(10);\n        }\n\n        @Actor\n        public void actor2()\n        {\n            sequence.addAndGet(20);\n        }\n\n        @Arbiter\n        public void arbiter(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * Updates to non-volatile long values in Java are issued as two separate 32-bit writes.\n     * SequenceUnsafe should store its underlying value as a volatile long and therefore should not experience this effect\n     * even when a non-volatile UNSAFE set method is used.\n     */\n    @JCStressTest\n    @Outcome(id = \"0\", expect = ACCEPTABLE, desc = \"Seeing the default value: writer had not acted yet.\")\n    @Outcome(id = \"-1\", expect = ACCEPTABLE, desc = \"Seeing the full value.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @Ref(\"https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.7\")\n    @State\n    public static class LongFullSet\n    {\n        SequenceUnsafe sequence = new SequenceUnsafe(0);\n\n        @Actor\n        public void writer()\n        {\n            sequence.set(0xFFFFFFFF_FFFFFFFFL);\n        }\n\n        @Actor\n        public void reader(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * Updates to non-volatile long values in Java are issued as two separate 32-bit writes.\n     * SequenceUnsafe should store its underlying value as a volatile long and therefore should not experience this effect.\n     */\n    @JCStressTest\n    @Outcome(id = \"0\", expect = ACCEPTABLE, desc = \"Seeing the default value: writer had not acted yet.\")\n    @Outcome(id = \"-1\", expect = ACCEPTABLE, desc = \"Seeing the full value.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @Ref(\"https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.7\")\n    @State\n    public static class LongFullSetVolatile\n    {\n        SequenceUnsafe sequence = new SequenceUnsafe(0);\n\n        @Actor\n        public void writer()\n        {\n            sequence.setVolatile(0xFFFFFFFF_FFFFFFFFL);\n        }\n\n        @Actor\n        public void reader(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * Updates to non-volatile long values in Java are issued as two separate 32-bit writes.\n     * SequenceUnsafe should store its underlying value as a volatile long and therefore should not experience this effect.\n     */\n    @JCStressTest\n    @Outcome(id = \"0\", expect = ACCEPTABLE, desc = \"Seeing the default value: writer had not acted yet.\")\n    @Outcome(id = \"-1\", expect = ACCEPTABLE, desc = \"Seeing the full value.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @Ref(\"https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.7\")\n    @State\n    public static class LongFullCompareAndSet\n    {\n        SequenceUnsafe sequence = new SequenceUnsafe(0);\n\n        @Actor\n        public void writer()\n        {\n            sequence.compareAndSet(0, 0xFFFFFFFF_FFFFFFFFL);\n        }\n\n        @Actor\n        public void reader(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n\n    /**\n     * In absence of synchronization, the order of independent reads is undefined.\n     * In our case, the value in SequenceUnsafe is volatile which mandates the writes to the same\n     * variable to be observed in a total order (that implies that _observers_ are also ordered)\n     */\n    @JCStressTest\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"1, 1\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"0, 1\", expect = ACCEPTABLE, desc = \"Doing first read early, not surprising.\")\n    @Outcome(id = \"1, 0\", expect = FORBIDDEN, desc = \"Violates coherence.\")\n    @State\n    public static class SameVolatileRead\n    {\n        private final Holder h1 = new Holder();\n        private final Holder h2 = h1;\n\n        private static class Holder\n        {\n            SequenceUnsafe sequence = new SequenceUnsafe(0);\n        }\n\n        @Actor\n        public void actor1()\n        {\n            h1.sequence.set(1);\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            Holder h1 = this.h1;\n            Holder h2 = this.h2;\n\n            r.r1 = h1.sequence.get();\n            r.r2 = h2.sequence.get();\n        }\n    }\n\n\n    /**\n     * The value field in SequenceUnsafe is volatile so we should never see an update to it without seeing the update to a\n     * previously set value also.\n     *\n     * <p>If the value was not volatile there would be no ordering rules stopping it being seen updated before the\n     * other value.\n     */\n    @JCStressTest\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"1, 1\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"0, 1\", expect = ACCEPTABLE, desc = \"Caught in the middle: $x is visible, $y is not.\")\n    @Outcome(id = \"1, 0\", expect = FORBIDDEN, desc = \"Seeing $y, but not $x!\")\n    @State\n    public static class SetVolatileGuard\n    {\n        long x = 0;\n        SequenceUnsafe y = new SequenceUnsafe(0);\n\n        @Actor\n        public void actor1()\n        {\n            x = 1;\n            y.setVolatile(1);\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            r.r1 = y.get();\n            r.r2 = x;\n        }\n    }\n\n    /**\n     * The value field in SequenceUnsafe is volatile so we should never see an update to it without seeing the update to a\n     * previously set value also.\n     *\n     * <p>If the value was not volatile there would be no ordering rules stopping it being seen updated before the\n     * other value.\n     *\n     * <p>This is a property of the field, not a property of the method used to set the value of it.\n     */\n    @JCStressTest\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"1, 1\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"0, 1\", expect = ACCEPTABLE, desc = \"Caught in the middle: $x is visible, $y is not.\")\n    @Outcome(id = \"1, 0\", expect = FORBIDDEN, desc = \"Seeing $y, but not $x!\")\n    @State\n    public static class SetGuard\n    {\n        long x = 0;\n        SequenceUnsafe y = new SequenceUnsafe(0);\n\n        @Actor\n        public void actor1()\n        {\n            x = 1;\n            y.set(1);\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            r.r1 = y.get();\n            r.r2 = x;\n        }\n    }\n\n\n    /**\n     * Volatile setting will experience total ordering.\n     */\n    @JCStressTest\n    @Outcome(id = {\"0, 1\", \"1, 0\", \"1, 1\"}, expect = ACCEPTABLE, desc = \"Trivial under sequential consistency\")\n    @Outcome(id = \"0, 0\", expect = FORBIDDEN, desc = \"Violates sequential consistency\")\n    @State\n    public static class SetVolatileDekker\n    {\n        SequenceUnsafe x = new SequenceUnsafe(0);\n        SequenceUnsafe y = new SequenceUnsafe(0);\n\n        @Actor\n        public void actor1(final JJ_Result r)\n        {\n            x.setVolatile(1);\n            r.r1 = y.get();\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            y.setVolatile(1);\n            r.r2 = x.get();\n\n        }\n    }\n\n    /**\n     * Non-volatile setting will not experience total ordering, those gets can be re-ordered and happen before either set.\n     */\n    @JCStressTest\n    @Outcome(id = {\"0, 1\", \"1, 0\", \"1, 1\"}, expect = ACCEPTABLE, desc = \"Trivial under sequential consistency\")\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE_INTERESTING, desc = \"Violates sequential consistency\")\n    @State\n    public static class SetDekker\n    {\n        SequenceUnsafe x = new SequenceUnsafe(0);\n        SequenceUnsafe y = new SequenceUnsafe(0);\n\n        @Actor\n        public void actor1(final JJ_Result r)\n        {\n            x.set(1);\n            r.r1 = y.get();\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            y.set(1);\n            r.r2 = x.get();\n        }\n    }\n}\n"
  },
  {
    "path": "src/jcstress/java/com/lmax/disruptor/SequenceStressVarHandle.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.alternatives.SequenceVarHandle;\nimport org.openjdk.jcstress.annotations.Actor;\nimport org.openjdk.jcstress.annotations.Arbiter;\nimport org.openjdk.jcstress.annotations.JCStressTest;\nimport org.openjdk.jcstress.annotations.Outcome;\nimport org.openjdk.jcstress.annotations.Ref;\nimport org.openjdk.jcstress.annotations.State;\nimport org.openjdk.jcstress.infra.results.JJ_Result;\nimport org.openjdk.jcstress.infra.results.J_Result;\nimport org.openjdk.jcstress.infra.results.ZZJ_Result;\n\nimport static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE;\nimport static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE_INTERESTING;\nimport static org.openjdk.jcstress.annotations.Expect.FORBIDDEN;\n\npublic class SequenceStressVarHandle\n{\n    /**\n     * `SequenceVarHandle::incrementAndGet` is atomic and should never lose an update, even with multiple threads racing.\n     */\n    @JCStressTest\n    @Outcome(id = \"1\", expect = FORBIDDEN, desc = \"One update lost.\")\n    @Outcome(id = \"2\", expect = ACCEPTABLE, desc = \"Both updates.\")\n    @State\n    public static class IncrementAndGet\n    {\n        SequenceVarHandle sequence = new SequenceVarHandle(0);\n\n        @Actor\n        public void actor1()\n        {\n            sequence.incrementAndGet();\n        }\n\n        @Actor\n        public void actor2()\n        {\n            sequence.incrementAndGet();\n        }\n\n        @Arbiter\n        public void arbiter(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * `SequenceVarHandle::compareAndSet` is atomic and should never lose an update, even with multiple threads racing.\n     */\n    @JCStressTest\n    @Outcome(id = {\"true, false, 10\", \"false, true, 20\"}, expect = ACCEPTABLE, desc = \"Either updated.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @State\n    public static class CompareAndSet\n    {\n        SequenceVarHandle sequence = new SequenceVarHandle(0);\n\n        @Actor\n        public void actor1(final ZZJ_Result r)\n        {\n            r.r1 = sequence.compareAndSet(0, 10);\n        }\n\n        @Actor\n        public void actor2(final ZZJ_Result r)\n        {\n            r.r2 = sequence.compareAndSet(0, 20);\n        }\n\n        @Arbiter\n        public void arbiter(final ZZJ_Result r)\n        {\n            r.r3 = sequence.get();\n        }\n    }\n\n    /**\n     * `SequenceVarHandle::addAndGet` is atomic and should never lose an update, even with multiple threads racing.\n     */\n    @JCStressTest\n    @Outcome(id = \"10\", expect = FORBIDDEN, desc = \"One update lost.\")\n    @Outcome(id = \"20\", expect = FORBIDDEN, desc = \"One update lost.\")\n    @Outcome(id = \"30\", expect = ACCEPTABLE, desc = \"Both updates.\")\n    @State\n    public static class AddAndGet\n    {\n        SequenceVarHandle sequence = new SequenceVarHandle(0);\n\n        @Actor\n        public void actor1()\n        {\n            sequence.addAndGet(10);\n        }\n\n        @Actor\n        public void actor2()\n        {\n            sequence.addAndGet(20);\n        }\n\n        @Arbiter\n        public void arbiter(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * Updates to non-volatile long values in Java are issued as two separate 32-bit writes.\n     * SequenceVarHandle should store its underlying value as a volatile long and therefore should not experience this effect\n     * even when a non-volatile UNSAFE set method is used.\n     */\n    @JCStressTest\n    @Outcome(id = \"0\", expect = ACCEPTABLE, desc = \"Seeing the default value: writer had not acted yet.\")\n    @Outcome(id = \"-1\", expect = ACCEPTABLE, desc = \"Seeing the full value.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @Ref(\"https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.7\")\n    @State\n    public static class LongFullSet\n    {\n        SequenceVarHandle sequence = new SequenceVarHandle(0);\n\n        @Actor\n        public void writer()\n        {\n            sequence.set(0xFFFFFFFF_FFFFFFFFL);\n        }\n\n        @Actor\n        public void reader(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * Updates to non-volatile long values in Java are issued as two separate 32-bit writes.\n     * SequenceVarHandle should store its underlying value as a volatile long and therefore should not experience this effect.\n     */\n    @JCStressTest\n    @Outcome(id = \"0\", expect = ACCEPTABLE, desc = \"Seeing the default value: writer had not acted yet.\")\n    @Outcome(id = \"-1\", expect = ACCEPTABLE, desc = \"Seeing the full value.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @Ref(\"https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.7\")\n    @State\n    public static class LongFullSetVolatile\n    {\n        SequenceVarHandle sequence = new SequenceVarHandle(0);\n\n        @Actor\n        public void writer()\n        {\n            sequence.setVolatile(0xFFFFFFFF_FFFFFFFFL);\n        }\n\n        @Actor\n        public void reader(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * Updates to non-volatile long values in Java are issued as two separate 32-bit writes.\n     * SequenceVarHandle should store its underlying value as a volatile long and therefore should not experience this effect.\n     */\n    @JCStressTest\n    @Outcome(id = \"0\", expect = ACCEPTABLE, desc = \"Seeing the default value: writer had not acted yet.\")\n    @Outcome(id = \"-1\", expect = ACCEPTABLE, desc = \"Seeing the full value.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @Ref(\"https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.7\")\n    @State\n    public static class LongFullCompareAndSet\n    {\n        SequenceVarHandle sequence = new SequenceVarHandle(0);\n\n        @Actor\n        public void writer()\n        {\n            sequence.compareAndSet(0, 0xFFFFFFFF_FFFFFFFFL);\n        }\n\n        @Actor\n        public void reader(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n\n    /**\n     * In absence of synchronization, the order of independent reads is undefined.\n     * In our case, the value in SequenceVarHandle is volatile which mandates the writes to the same\n     * variable to be observed in a total order (that implies that _observers_ are also ordered)\n     */\n    @JCStressTest\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"1, 1\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"0, 1\", expect = ACCEPTABLE, desc = \"Doing first read early, not surprising.\")\n    @Outcome(id = \"1, 0\", expect = FORBIDDEN, desc = \"Violates coherence.\")\n    @State\n    public static class SameVolatileRead\n    {\n        private final Holder h1 = new Holder();\n        private final Holder h2 = h1;\n\n        private static class Holder\n        {\n            SequenceVarHandle sequence = new SequenceVarHandle(0);\n        }\n\n        @Actor\n        public void actor1()\n        {\n            h1.sequence.set(1);\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            Holder h1 = this.h1;\n            Holder h2 = this.h2;\n\n            r.r1 = h1.sequence.get();\n            r.r2 = h2.sequence.get();\n        }\n    }\n\n\n    /**\n     * The value field in SequenceVarHandle is volatile so we should never see an update to it without seeing the update to a\n     * previously set value also.\n     *\n     * <p>If the value was not volatile there would be no ordering rules stopping it being seen updated before the\n     * other value.\n     */\n    @JCStressTest\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"1, 1\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"0, 1\", expect = ACCEPTABLE, desc = \"Caught in the middle: $x is visible, $y is not.\")\n    @Outcome(id = \"1, 0\", expect = FORBIDDEN, desc = \"Seeing $y, but not $x!\")\n    @State\n    public static class SetVolatileGuard\n    {\n        long x = 0;\n        SequenceVarHandle y = new SequenceVarHandle(0);\n\n        @Actor\n        public void actor1()\n        {\n            x = 1;\n            y.setVolatile(1);\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            r.r1 = y.get();\n            r.r2 = x;\n        }\n    }\n\n    /**\n     * The value field in SequenceVarHandle is volatile so we should never see an update to it without seeing the update to a\n     * previously set value also.\n     *\n     * <p>If the value was not volatile there would be no ordering rules stopping it being seen updated before the\n     * other value.\n     *\n     * <p>This is a property of the field, not a property of the method used to set the value of it.\n     */\n    @JCStressTest\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"1, 1\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"0, 1\", expect = ACCEPTABLE, desc = \"Caught in the middle: $x is visible, $y is not.\")\n    @Outcome(id = \"1, 0\", expect = FORBIDDEN, desc = \"Seeing $y, but not $x!\")\n    @State\n    public static class SetGuard\n    {\n        long x = 0;\n        SequenceVarHandle y = new SequenceVarHandle(0);\n\n        @Actor\n        public void actor1()\n        {\n            x = 1;\n            y.set(1);\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            r.r1 = y.get();\n            r.r2 = x;\n        }\n    }\n\n\n    /**\n     * Volatile setting will experience total ordering.\n     */\n    @JCStressTest\n    @Outcome(id = {\"0, 1\", \"1, 0\", \"1, 1\"}, expect = ACCEPTABLE, desc = \"Trivial under sequential consistency\")\n    @Outcome(id = \"0, 0\", expect = FORBIDDEN, desc = \"Violates sequential consistency\")\n    @State\n    public static class SetVolatileDekker\n    {\n        SequenceVarHandle x = new SequenceVarHandle(0);\n        SequenceVarHandle y = new SequenceVarHandle(0);\n\n        @Actor\n        public void actor1(final JJ_Result r)\n        {\n            x.setVolatile(1);\n            r.r1 = y.get();\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            y.setVolatile(1);\n            r.r2 = x.get();\n\n        }\n    }\n\n    /**\n     * Non-volatile setting will not experience total ordering, those gets can be re-ordered and happen before either set.\n     */\n    @JCStressTest\n    @Outcome(id = {\"0, 1\", \"1, 0\", \"1, 1\"}, expect = ACCEPTABLE, desc = \"Trivial under sequential consistency\")\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE_INTERESTING, desc = \"Violates sequential consistency\")\n    @State\n    public static class SetDekker\n    {\n        SequenceVarHandle x = new SequenceVarHandle(0);\n        SequenceVarHandle y = new SequenceVarHandle(0);\n\n        @Actor\n        public void actor1(final JJ_Result r)\n        {\n            x.set(1);\n            r.r1 = y.get();\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            y.set(1);\n            r.r2 = x.get();\n        }\n    }\n}\n"
  },
  {
    "path": "src/jcstress/java/com/lmax/disruptor/SequenceStressVarHandleBarrier.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.alternatives.SequenceVarHandleBarrier;\nimport org.openjdk.jcstress.annotations.Actor;\nimport org.openjdk.jcstress.annotations.Arbiter;\nimport org.openjdk.jcstress.annotations.JCStressTest;\nimport org.openjdk.jcstress.annotations.Outcome;\nimport org.openjdk.jcstress.annotations.Ref;\nimport org.openjdk.jcstress.annotations.State;\nimport org.openjdk.jcstress.infra.results.JJ_Result;\nimport org.openjdk.jcstress.infra.results.J_Result;\nimport org.openjdk.jcstress.infra.results.ZZJ_Result;\n\nimport static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE;\nimport static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE_INTERESTING;\nimport static org.openjdk.jcstress.annotations.Expect.FORBIDDEN;\n\npublic class SequenceStressVarHandleBarrier\n{\n    /**\n     * `com.lmax.disruptor.alternatives.SequenceVarHandleBarrier::incrementAndGet` is atomic and should never lose an update, even with multiple threads racing.\n     */\n    @JCStressTest\n    @Outcome(id = \"1\", expect = FORBIDDEN, desc = \"One update lost.\")\n    @Outcome(id = \"2\", expect = ACCEPTABLE, desc = \"Both updates.\")\n    @State\n    public static class IncrementAndGet\n    {\n        SequenceVarHandleBarrier sequence = new SequenceVarHandleBarrier(0);\n\n        @Actor\n        public void actor1()\n        {\n            sequence.incrementAndGet();\n        }\n\n        @Actor\n        public void actor2()\n        {\n            sequence.incrementAndGet();\n        }\n\n        @Arbiter\n        public void arbiter(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * `SequenceVarHandleBarrier::compareAndSet` is atomic and should never lose an update, even with multiple threads racing.\n     */\n    @JCStressTest\n    @Outcome(id = {\"true, false, 10\", \"false, true, 20\"}, expect = ACCEPTABLE, desc = \"Either updated.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @State\n    public static class CompareAndSet\n    {\n        SequenceVarHandleBarrier sequence = new SequenceVarHandleBarrier(0);\n\n        @Actor\n        public void actor1(final ZZJ_Result r)\n        {\n            r.r1 = sequence.compareAndSet(0, 10);\n        }\n\n        @Actor\n        public void actor2(final ZZJ_Result r)\n        {\n            r.r2 = sequence.compareAndSet(0, 20);\n        }\n\n        @Arbiter\n        public void arbiter(final ZZJ_Result r)\n        {\n            r.r3 = sequence.get();\n        }\n    }\n\n    /**\n     * `SequenceVarHandleBarrier::addAndGet` is atomic and should never lose an update, even with multiple threads racing.\n     */\n    @JCStressTest\n    @Outcome(id = \"10\", expect = FORBIDDEN, desc = \"One update lost.\")\n    @Outcome(id = \"20\", expect = FORBIDDEN, desc = \"One update lost.\")\n    @Outcome(id = \"30\", expect = ACCEPTABLE, desc = \"Both updates.\")\n    @State\n    public static class AddAndGet\n    {\n        SequenceVarHandleBarrier sequence = new SequenceVarHandleBarrier(0);\n\n        @Actor\n        public void actor1()\n        {\n            sequence.addAndGet(10);\n        }\n\n        @Actor\n        public void actor2()\n        {\n            sequence.addAndGet(20);\n        }\n\n        @Arbiter\n        public void arbiter(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * Updates to non-volatile long values in Java are issued as two separate 32-bit writes.\n     * SequenceVarHandleBarrier should store its underlying value as a volatile long and therefore should not experience this effect\n     * even when a non-volatile UNSAFE set method is used.\n     */\n    @JCStressTest\n    @Outcome(id = \"0\", expect = ACCEPTABLE, desc = \"Seeing the default value: writer had not acted yet.\")\n    @Outcome(id = \"-1\", expect = ACCEPTABLE, desc = \"Seeing the full value.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @Ref(\"https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.7\")\n    @State\n    public static class LongFullSet\n    {\n        SequenceVarHandleBarrier sequence = new SequenceVarHandleBarrier(0);\n\n        @Actor\n        public void writer()\n        {\n            sequence.set(0xFFFFFFFF_FFFFFFFFL);\n        }\n\n        @Actor\n        public void reader(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * Updates to non-volatile long values in Java are issued as two separate 32-bit writes.\n     * SequenceVarHandleBarrier should store its underlying value as a volatile long and therefore should not experience this effect.\n     */\n    @JCStressTest\n    @Outcome(id = \"0\", expect = ACCEPTABLE, desc = \"Seeing the default value: writer had not acted yet.\")\n    @Outcome(id = \"-1\", expect = ACCEPTABLE, desc = \"Seeing the full value.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @Ref(\"https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.7\")\n    @State\n    public static class LongFullSetVolatile\n    {\n        SequenceVarHandleBarrier sequence = new SequenceVarHandleBarrier(0);\n\n        @Actor\n        public void writer()\n        {\n            sequence.setVolatile(0xFFFFFFFF_FFFFFFFFL);\n        }\n\n        @Actor\n        public void reader(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n    /**\n     * Updates to non-volatile long values in Java are issued as two separate 32-bit writes.\n     * SequenceVarHandleBarrier should store its underlying value as a volatile long and therefore should not experience this effect.\n     */\n    @JCStressTest\n    @Outcome(id = \"0\", expect = ACCEPTABLE, desc = \"Seeing the default value: writer had not acted yet.\")\n    @Outcome(id = \"-1\", expect = ACCEPTABLE, desc = \"Seeing the full value.\")\n    @Outcome(expect = FORBIDDEN, desc = \"Other cases are forbidden.\")\n    @Ref(\"https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.7\")\n    @State\n    public static class LongFullCompareAndSet\n    {\n        SequenceVarHandleBarrier sequence = new SequenceVarHandleBarrier(0);\n\n        @Actor\n        public void writer()\n        {\n            sequence.compareAndSet(0, 0xFFFFFFFF_FFFFFFFFL);\n        }\n\n        @Actor\n        public void reader(final J_Result r)\n        {\n            r.r1 = sequence.get();\n        }\n    }\n\n\n    /**\n     * In absence of synchronization, the order of independent reads is undefined.\n     * In our case, the value in SequenceVarHandleBarrier is volatile which mandates the writes to the same\n     * variable to be observed in a total order (that implies that _observers_ are also ordered)\n     */\n    @JCStressTest\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"1, 1\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"0, 1\", expect = ACCEPTABLE, desc = \"Doing first read early, not surprising.\")\n    @Outcome(id = \"1, 0\", expect = FORBIDDEN, desc = \"Violates coherence.\")\n    @State\n    public static class SameVolatileRead\n    {\n        private final Holder h1 = new Holder();\n        private final Holder h2 = h1;\n\n        private static class Holder\n        {\n            SequenceVarHandleBarrier sequence = new SequenceVarHandleBarrier(0);\n        }\n\n        @Actor\n        public void actor1()\n        {\n            h1.sequence.set(1);\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            Holder h1 = this.h1;\n            Holder h2 = this.h2;\n\n            r.r1 = h1.sequence.get();\n            r.r2 = h2.sequence.get();\n        }\n    }\n\n\n    /**\n     * The value field in SequenceVarHandleBarrier is volatile so we should never see an update to it without seeing the update to a\n     * previously set value also.\n     *\n     * <p>If the value was not volatile there would be no ordering rules stopping it being seen updated before the\n     * other value.\n     */\n    @JCStressTest\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"1, 1\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"0, 1\", expect = ACCEPTABLE, desc = \"Caught in the middle: $x is visible, $y is not.\")\n    @Outcome(id = \"1, 0\", expect = FORBIDDEN, desc = \"Seeing $y, but not $x!\")\n    @State\n    public static class SetVolatileGuard\n    {\n        long x = 0;\n        SequenceVarHandleBarrier y = new SequenceVarHandleBarrier(0);\n\n        @Actor\n        public void actor1()\n        {\n            x = 1;\n            y.setVolatile(1);\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            r.r1 = y.get();\n            r.r2 = x;\n        }\n    }\n\n    /**\n     * The value field in SequenceVarHandleBarrier is volatile so we should never see an update to it without seeing the update to a\n     * previously set value also.\n     *\n     * <p>If the value was not volatile there would be no ordering rules stopping it being seen updated before the\n     * other value.\n     *\n     * <p>This is a property of the field, not a property of the method used to set the value of it.\n     */\n    @JCStressTest\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE, desc = \"Doing both reads early.\")\n    @Outcome(id = \"1, 1\", expect = ACCEPTABLE, desc = \"Doing both reads late.\")\n    @Outcome(id = \"0, 1\", expect = ACCEPTABLE, desc = \"Caught in the middle: $x is visible, $y is not.\")\n    @Outcome(id = \"1, 0\", expect = FORBIDDEN, desc = \"Seeing $y, but not $x!\")\n    @State\n    public static class SetGuard\n    {\n        long x = 0;\n        SequenceVarHandleBarrier y = new SequenceVarHandleBarrier(0);\n\n        @Actor\n        public void actor1()\n        {\n            x = 1;\n            y.set(1);\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            r.r1 = y.get();\n            r.r2 = x;\n        }\n    }\n\n\n    /**\n     * Volatile setting will experience total ordering.\n     */\n    @JCStressTest\n    @Outcome(id = {\"0, 1\", \"1, 0\", \"1, 1\"}, expect = ACCEPTABLE, desc = \"Trivial under sequential consistency\")\n    @Outcome(id = \"0, 0\", expect = FORBIDDEN, desc = \"Violates sequential consistency\")\n    @State\n    public static class SetVolatileDekker\n    {\n        SequenceVarHandleBarrier x = new SequenceVarHandleBarrier(0);\n        SequenceVarHandleBarrier y = new SequenceVarHandleBarrier(0);\n\n        @Actor\n        public void actor1(final JJ_Result r)\n        {\n            x.setVolatile(1);\n            r.r1 = y.get();\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            y.setVolatile(1);\n            r.r2 = x.get();\n\n        }\n    }\n\n    /**\n     * Non-volatile setting will not experience total ordering, those gets can be re-ordered and happen before either set.\n     */\n    @JCStressTest\n    @Outcome(id = {\"0, 1\", \"1, 0\", \"1, 1\"}, expect = ACCEPTABLE, desc = \"Trivial under sequential consistency\")\n    @Outcome(id = \"0, 0\", expect = ACCEPTABLE_INTERESTING, desc = \"Violates sequential consistency\")\n    @State\n    public static class SetDekker\n    {\n        SequenceVarHandleBarrier x = new SequenceVarHandleBarrier(0);\n        SequenceVarHandleBarrier y = new SequenceVarHandleBarrier(0);\n\n        @Actor\n        public void actor1(final JJ_Result r)\n        {\n            x.set(1);\n            r.r1 = y.get();\n        }\n\n        @Actor\n        public void actor2(final JJ_Result r)\n        {\n            y.set(1);\n            r.r2 = x.get();\n        }\n    }\n}\n"
  },
  {
    "path": "src/jmh/java/com/lmax/disruptor/ArrayAccessBenchmark.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.util.SimpleEvent;\nimport com.lmax.disruptor.util.UnsafeAccess;\nimport net.openhft.affinity.Affinity;\nimport net.openhft.affinity.AffinityLock;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Measurement;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.TearDown;\nimport org.openjdk.jmh.annotations.Threads;\nimport org.openjdk.jmh.annotations.Warmup;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.RunnerException;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\nimport sun.misc.Unsafe;\n\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.VarHandle;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.stream.Collectors;\n\nimport static java.util.function.Predicate.not;\n\n@SuppressWarnings(\"unused\")\n@BenchmarkMode(Mode.Throughput)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Warmup(iterations = 5, time = 1)\n@Measurement(iterations = 5, time = 1)\n@Fork(2)\n@Threads(1)\n@State(Scope.Thread)\npublic class ArrayAccessBenchmark\n{\n    // To run this on a tuned system with benchmark threads pinned to isolated cpus:\n    // Run the JMH process with an env var defining the isolated cpu list, e.g. ISOLATED_CPUS=38,40,42,44,46,48 java -jar disruptor-jmh.jar\n    private static final List<Integer> ISOLATED_CPUS = Arrays.stream(System.getenv().getOrDefault(\"ISOLATED_CPUS\", \"\").split(\",\"))\n            .map(String::trim)\n            .filter(not(String::isBlank))\n            .map(Integer::valueOf)\n            .collect(Collectors.toList());\n\n    private static final AtomicInteger THREAD_COUNTER = new AtomicInteger();\n\n    @State(Scope.Thread)\n    public static class ThreadPinningState\n    {\n        int threadId = THREAD_COUNTER.getAndIncrement();\n        private AffinityLock affinityLock;\n\n        @Setup\n        public void setup()\n        {\n            if (ISOLATED_CPUS.size() > 0)\n            {\n                if (threadId > ISOLATED_CPUS.size())\n                {\n                    throw new IllegalArgumentException(\n                            String.format(\"Benchmark uses at least %d threads, only defined %d isolated cpus\",\n                                    threadId,\n                                    ISOLATED_CPUS.size()\n                            ));\n                }\n\n                final Integer cpuId = ISOLATED_CPUS.get(threadId);\n                affinityLock = AffinityLock.acquireLock(cpuId);\n                System.out.printf(\"Attempted to set thread affinity for %s to %d, success = %b%n\",\n                        Thread.currentThread().getName(),\n                        cpuId,\n                        affinityLock.isAllocated()\n                );\n            }\n            else\n            {\n                System.err.printf(\"ISOLATED_CPUS environment variable not defined, running thread %s (id=%d) on scheduler-defined CPU:%d%n \",\n                        Thread.currentThread().getName(),\n                        threadId,\n                        Affinity.getCpu());\n            }\n        }\n\n        @TearDown\n        public void teardown()\n        {\n            if (ISOLATED_CPUS.size() > 0)\n            {\n                affinityLock.release();\n            }\n        }\n    }\n\n    private static final int EVENT_COUNT = 64;\n    private static final int INDEX_MASK = EVENT_COUNT - 1;\n    private final Object[] entries = new Object[EVENT_COUNT];\n    public int sequence;\n\n    private static final Unsafe UNSAFE = UnsafeAccess.getUnsafe();\n    private final int scale = UNSAFE.arrayIndexScale(Object[].class);\n    private final int offset = UNSAFE.arrayBaseOffset(Object[].class);\n\n    private final VarHandle varHandle = MethodHandles.arrayElementVarHandle(Object[].class);\n\n    private final MethodHandle methodHandle = MethodHandles.arrayElementGetter(Object[].class);\n\n    @Setup\n    public void setup()\n    {\n        for (int i = 0; i < EVENT_COUNT; i++)\n        {\n            SimpleEvent simpleEvent = new SimpleEvent();\n            simpleEvent.setValue(i);\n            entries[i] = simpleEvent;\n        }\n\n        sequence = 0;\n    }\n\n    @Benchmark\n    public Object standardArrayAccess(final ThreadPinningState t)\n    {\n        return entries[getNextSequence()];\n    }\n\n    @Benchmark\n    public Object unsafeArrayAccess(final ThreadPinningState t)\n    {\n        return UNSAFE.getObject(entries, offset + ((long) (getNextSequence()) * scale));\n    }\n\n    @Benchmark\n    public Object varHandleArrayAccess(final ThreadPinningState t)\n    {\n        return varHandle.get(entries, getNextSequence());\n    }\n\n    @Benchmark\n    public Object getterMethodHandleInvokeArrayAccess(final ThreadPinningState t) throws Throwable\n    {\n        return methodHandle.invoke(entries, getNextSequence());\n    }\n\n    @Benchmark\n    public Object getterMethodHandleInvokeExactArrayAccess(final ThreadPinningState t) throws Throwable\n    {\n        return methodHandle.invokeExact(entries, getNextSequence());\n    }\n\n    private int getNextSequence()\n    {\n        return sequence++ & INDEX_MASK;\n    }\n\n    public static void main(final String[] args) throws RunnerException\n    {\n        Options opt = new OptionsBuilder()\n                .include(ArrayAccessBenchmark.class.getSimpleName())\n                .build();\n        new Runner(opt).run();\n    }\n}\n"
  },
  {
    "path": "src/jmh/java/com/lmax/disruptor/BlockingQueueBenchmark.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.util.Constants;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport com.lmax.disruptor.util.SimpleEvent;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.TearDown;\nimport org.openjdk.jmh.infra.Blackhole;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.RunnerException;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\n@BenchmarkMode(Mode.AverageTime)\n@OutputTimeUnit(TimeUnit.NANOSECONDS)\n@State(Scope.Thread)\n@Fork(1)\npublic class BlockingQueueBenchmark\n{\n    private BlockingQueue<SimpleEvent> arrayBlockingQueue;\n    private volatile boolean consumerRunning;\n    private SimpleEvent simpleEvent;\n\n    @Setup\n    public void setup(final Blackhole bh) throws InterruptedException\n    {\n        arrayBlockingQueue = new ArrayBlockingQueue<>(Constants.RINGBUFFER_SIZE);\n\n        final CountDownLatch consumerStartedLatch = new CountDownLatch(1);\n        final Thread eventHandler = DaemonThreadFactory.INSTANCE.newThread(() ->\n        {\n            consumerStartedLatch.countDown();\n            while (consumerRunning)\n            {\n                SimpleEvent event = arrayBlockingQueue.poll();\n                if (event != null)\n                {\n                    bh.consume(event);\n                }\n            }\n        });\n        consumerRunning = true;\n        eventHandler.start();\n        consumerStartedLatch.await();\n\n        simpleEvent = new SimpleEvent();\n        simpleEvent.setValue(0);\n    }\n\n    @Benchmark\n    public void producing() throws InterruptedException\n    {\n        if (!arrayBlockingQueue.offer(simpleEvent, 1, TimeUnit.SECONDS))\n        {\n            throw new IllegalStateException(\"Queue full, benchmark should not experience backpressure\");\n        }\n    }\n\n    @TearDown\n    public void tearDown()\n    {\n        consumerRunning = false;\n    }\n\n    public static void main(final String[] args) throws RunnerException\n    {\n        Options opt = new OptionsBuilder()\n                .include(BlockingQueueBenchmark.class.getSimpleName())\n                .forks(1)\n                .build();\n        new Runner(opt).run();\n    }\n}\n"
  },
  {
    "path": "src/jmh/java/com/lmax/disruptor/MultiProducerSequencerBenchmark.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.alternatives.MultiProducerSequencerUnsafe;\nimport com.lmax.disruptor.alternatives.MultiProducerSequencerVarHandle;\nimport net.openhft.affinity.Affinity;\nimport net.openhft.affinity.AffinityLock;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Group;\nimport org.openjdk.jmh.annotations.Measurement;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.TearDown;\nimport org.openjdk.jmh.annotations.Threads;\nimport org.openjdk.jmh.annotations.Warmup;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.RunnerException;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.stream.Collectors;\n\nimport static java.util.function.Predicate.not;\n\n@SuppressWarnings(\"unused\")\n@BenchmarkMode(Mode.Throughput)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Warmup(iterations = 5, time = 1)\n@Measurement(iterations = 5, time = 1)\n@Fork(2)\n@Threads(1)\npublic class MultiProducerSequencerBenchmark\n{\n    // To run this on a tuned system with benchmark threads pinned to isolated cpus:\n    // Run the JMH process with an env var defining the isolated cpu list, e.g. ISOLATED_CPUS=38,40,42,44,46,48 java -jar disruptor-jmh.jar\n    private static final List<Integer> ISOLATED_CPUS = Arrays.stream(System.getenv().getOrDefault(\"ISOLATED_CPUS\", \"\").split(\",\"))\n            .map(String::trim)\n            .filter(not(String::isBlank))\n            .map(Integer::valueOf)\n            .collect(Collectors.toList());\n\n    private static final AtomicInteger THREAD_COUNTER = new AtomicInteger();\n\n    @State(Scope.Thread)\n    public static class ThreadPinningState\n    {\n        int threadId = THREAD_COUNTER.getAndIncrement();\n        private AffinityLock affinityLock;\n\n        @Setup\n        public void setup()\n        {\n            if (ISOLATED_CPUS.size() > 0)\n            {\n                if (threadId > ISOLATED_CPUS.size())\n                {\n                    throw new IllegalArgumentException(\n                            String.format(\"Benchmark uses at least %d threads, only defined %d isolated cpus\",\n                                    threadId,\n                                    ISOLATED_CPUS.size()\n                            ));\n                }\n\n                final Integer cpuId = ISOLATED_CPUS.get(threadId);\n                affinityLock = AffinityLock.acquireLock(cpuId);\n                System.out.printf(\"Attempted to set thread affinity for %s to %d, success = %b%n\",\n                        Thread.currentThread().getName(),\n                        cpuId,\n                        affinityLock.isAllocated()\n                );\n            }\n            else\n            {\n                System.err.printf(\"ISOLATED_CPUS environment variable not defined, running thread %s (id=%d) on scheduler-defined CPU:%d%n \",\n                        Thread.currentThread().getName(),\n                        threadId,\n                        Affinity.getCpu());\n            }\n        }\n\n        @TearDown\n        public void teardown()\n        {\n            if (ISOLATED_CPUS.size() > 0)\n            {\n                affinityLock.release();\n            }\n        }\n    }\n\n    /*\n     * com.lmax.disruptor.alternatives.MultiProducerSequencerUnsafe (as of disruptor v3.4.2)\n     */\n    @State(Scope.Group)\n    public static class StateMultiProducerSequencerUnsafe\n    {\n        Sequencer value1 = new MultiProducerSequencerUnsafe(64, new BlockingWaitStrategy());\n        Sequencer value2 = new MultiProducerSequencerUnsafe(64, new BlockingWaitStrategy());\n    }\n\n    @Benchmark\n    @Group(\"SequenceUnsafe\")\n    public boolean read1(final StateMultiProducerSequencerUnsafe s, final ThreadPinningState t)\n    {\n        return s.value1.isAvailable(1);\n    }\n\n    @Benchmark\n    @Group(\"SequenceUnsafe\")\n    public boolean read2(final StateMultiProducerSequencerUnsafe s, final ThreadPinningState t)\n    {\n        return s.value1.isAvailable(1);\n    }\n\n    @Benchmark\n    @Group(\"SequenceUnsafe\")\n    public void setValue1A(final StateMultiProducerSequencerUnsafe s, final ThreadPinningState t)\n    {\n        s.value1.publish(1L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceUnsafe\")\n    public void setValue1B(final StateMultiProducerSequencerUnsafe s, final ThreadPinningState t)\n    {\n        s.value1.publish(2L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceUnsafe\")\n    public void setValue2A(final StateMultiProducerSequencerUnsafe s, final ThreadPinningState t)\n    {\n        s.value2.publish(1L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceUnsafe\")\n    public void setValue2B(final StateMultiProducerSequencerUnsafe s, final ThreadPinningState t)\n    {\n        s.value2.publish(2L);\n    }\n\n    /*\n     * com.lmax.disruptor.alternatives.StateSequenceVarHandle (as of disruptor v3.4.2)\n     */\n    @State(Scope.Group)\n    public static class StateMultiProducerSequencerVarHandle\n    {\n        Sequencer value1 = new MultiProducerSequencerVarHandle(64, new BlockingWaitStrategy());\n        Sequencer value2 = new MultiProducerSequencerVarHandle(64, new BlockingWaitStrategy());\n    }\n\n    @Benchmark\n    @Group(\"StateMultiProducerSequencerVarHandle\")\n    public boolean read1(final StateMultiProducerSequencerVarHandle s, final ThreadPinningState t)\n    {\n        return s.value1.isAvailable(1);\n    }\n\n    @Benchmark\n    @Group(\"StateMultiProducerSequencerVarHandle\")\n    public boolean read2(final StateMultiProducerSequencerVarHandle s, final ThreadPinningState t)\n    {\n        return s.value1.isAvailable(1);\n    }\n\n    @Benchmark\n    @Group(\"StateMultiProducerSequencerVarHandle\")\n    public void setValue1A(final StateMultiProducerSequencerVarHandle s, final ThreadPinningState t)\n    {\n        s.value1.publish(1L);\n    }\n\n    @Benchmark\n    @Group(\"StateMultiProducerSequencerVarHandle\")\n    public void setValue1B(final StateMultiProducerSequencerVarHandle s, final ThreadPinningState t)\n    {\n        s.value1.publish(2L);\n    }\n\n    @Benchmark\n    @Group(\"StateMultiProducerSequencerVarHandle\")\n    public void setValue2A(final StateMultiProducerSequencerVarHandle s, final ThreadPinningState t)\n    {\n        s.value2.publish(1L);\n    }\n\n    @Benchmark\n    @Group(\"StateMultiProducerSequencerVarHandle\")\n    public void setValue2B(final StateMultiProducerSequencerVarHandle s, final ThreadPinningState t)\n    {\n        s.value2.publish(2L);\n    }\n\n    public static void main(final String[] args) throws RunnerException\n    {\n        Options opt = new OptionsBuilder()\n                .include(MultiProducerSequencerBenchmark.class.getSimpleName())\n                .build();\n        new Runner(opt).run();\n    }\n}\n"
  },
  {
    "path": "src/jmh/java/com/lmax/disruptor/MultiProducerSingleConsumer.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.dsl.ProducerType;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport com.lmax.disruptor.util.SimpleEvent;\nimport com.lmax.disruptor.util.SimpleEventHandler;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OperationsPerInvocation;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.TearDown;\nimport org.openjdk.jmh.annotations.Threads;\nimport org.openjdk.jmh.infra.Blackhole;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.RunnerException;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.concurrent.TimeUnit;\n\n@BenchmarkMode(Mode.Throughput)\n@OutputTimeUnit(TimeUnit.MILLISECONDS)\n@State(Scope.Benchmark)\n@Fork(1)\npublic class MultiProducerSingleConsumer\n{\n    private RingBuffer<SimpleEvent> ringBuffer;\n    private Disruptor<SimpleEvent> disruptor;\n    private static final int BIG_BUFFER = 1 << 22;\n    private static final int BATCH_SIZE = 100;\n\n    @Setup\n    public void setup(final Blackhole bh)\n    {\n        disruptor = new Disruptor<>(SimpleEvent::new,\n                BIG_BUFFER,\n                DaemonThreadFactory.INSTANCE,\n                ProducerType.MULTI,\n                new BusySpinWaitStrategy());\n\n        disruptor.handleEventsWith(new SimpleEventHandler(bh));\n\n        ringBuffer = disruptor.start();\n    }\n\n    @Benchmark\n    @Threads(4)\n    public void producing()\n    {\n        long sequence = ringBuffer.next();\n        SimpleEvent simpleEvent = ringBuffer.get(sequence);\n        simpleEvent.setValue(0);\n        ringBuffer.publish(sequence);\n    }\n\n    @Benchmark\n    @Threads(4)\n    @OperationsPerInvocation(BATCH_SIZE)\n    public void producingBatch()\n    {\n        long hi = ringBuffer.next(BATCH_SIZE);\n        long lo = hi - (BATCH_SIZE - 1);\n        for (long sequence = lo; sequence <= hi; sequence++)\n        {\n            SimpleEvent simpleEvent = ringBuffer.get(sequence);\n            simpleEvent.setValue(0);\n        }\n        ringBuffer.publish(lo, hi);\n    }\n\n    @TearDown\n    public void tearDown()\n    {\n        disruptor.shutdown();\n    }\n\n    public static void main(final String[] args) throws RunnerException\n    {\n        Options opt = new OptionsBuilder()\n                .include(MultiProducerSingleConsumer.class.getSimpleName())\n                .build();\n        new Runner(opt).run();\n    }\n}\n"
  },
  {
    "path": "src/jmh/java/com/lmax/disruptor/RingBufferBenchmark.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.alternatives.RingBufferArray;\nimport com.lmax.disruptor.alternatives.RingBufferUnsafe;\nimport com.lmax.disruptor.support.DummyWaitStrategy;\nimport com.lmax.disruptor.support.StubEvent;\nimport net.openhft.affinity.Affinity;\nimport net.openhft.affinity.AffinityLock;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Group;\nimport org.openjdk.jmh.annotations.Measurement;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.TearDown;\nimport org.openjdk.jmh.annotations.Threads;\nimport org.openjdk.jmh.annotations.Warmup;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.RunnerException;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.stream.Collectors;\n\nimport static java.util.function.Predicate.not;\n\n@SuppressWarnings(\"ALL\")\n@BenchmarkMode(Mode.Throughput)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Warmup(iterations = 5, time = 1)\n@Measurement(iterations = 5, time = 1)\n@Fork(2)\n@Threads(1)\npublic class RingBufferBenchmark\n{\n    // To run this on a tuned system with benchmark threads pinned to isolated cpus:\n    // Run the JMH process with an env var defining the isolated cpu list, e.g. ISOLATED_CPUS=38,40,42,44,46,48 java -jar disruptor-jmh.jar\n    private static final List<Integer> ISOLATED_CPUS = Arrays.stream(System.getenv().getOrDefault(\"ISOLATED_CPUS\", \"\").split(\",\"))\n            .map(String::trim)\n            .filter(not(String::isBlank))\n            .map(Integer::valueOf)\n            .collect(Collectors.toList());\n\n    private static final AtomicInteger THREAD_COUNTER = new AtomicInteger();\n\n    @State(Scope.Thread)\n    public static class ThreadPinningState\n    {\n        int threadId = THREAD_COUNTER.getAndIncrement();\n        private AffinityLock affinityLock;\n\n        @Setup\n        public void setup()\n        {\n            if (ISOLATED_CPUS.size() > 0)\n            {\n                if (threadId > ISOLATED_CPUS.size())\n                {\n                    throw new IllegalArgumentException(\n                            String.format(\"Benchmark uses at least %d threads, only defined %d isolated cpus\",\n                                    threadId,\n                                    ISOLATED_CPUS.size()\n                            ));\n                }\n\n                final Integer cpuId = ISOLATED_CPUS.get(threadId);\n                affinityLock = AffinityLock.acquireLock(cpuId);\n                System.out.printf(\"Attempted to set thread affinity for %s to %d, success = %b%n\",\n                        Thread.currentThread().getName(),\n                        cpuId,\n                        affinityLock.isAllocated()\n                );\n            }\n            else\n            {\n                System.err.printf(\"ISOLATED_CPUS environment variable not defined, running thread %s (id=%d) on scheduler-defined CPU:%d%n \",\n                        Thread.currentThread().getName(),\n                        threadId,\n                        Affinity.getCpu());\n            }\n        }\n\n        @TearDown\n        public void teardown()\n        {\n            if (ISOLATED_CPUS.size() > 0)\n            {\n                affinityLock.release();\n            }\n        }\n    }\n\n    /*\n     * APPROACH 1: RingBufferUnsafe - Using the unsafe API to avoid bounds-checking, as was the case for Disruptor 3.x\n     */\n\n    @State(Scope.Group)\n    public static class StateRingBufferUnsafe\n    {\n        RingBufferUnsafe<Object> ringBufferUnsafe = new RingBufferUnsafe<>(\n                () -> new StubEvent(-1),\n                new SingleProducerSequencer(128, new DummyWaitStrategy()));\n    }\n\n    @Benchmark\n    @Group(\"RingBufferUnsafe\")\n    public Object readUnsafe(final StateRingBufferUnsafe ringBufferUnsafe, final ThreadPinningState t)\n    {\n        return ringBufferUnsafe.ringBufferUnsafe.get(64);\n    }\n\n    @Benchmark\n    @Group(\"RingBufferUnsafe\")\n    public void writeUnsafe(final StateRingBufferUnsafe ringBufferUnsafe, final ThreadPinningState t)\n    {\n        ringBufferUnsafe.ringBufferUnsafe.publish(64);\n    }\n\n    /*\n     * APPROACH 2: RingBufferArray - There is no support for non-bounds-checked array element access as there was via\n     * unsafe. So the simplest approach is to go back to a plain array and index to elements.\n     */\n\n    @State(Scope.Group)\n    public static class StateRingBufferArray\n    {\n        RingBufferArray<Object> ringBufferVarHandle = new RingBufferArray<>(\n                () -> new StubEvent(-1),\n                new SingleProducerSequencer(128, new DummyWaitStrategy())\n        );\n    }\n\n    @Benchmark\n    @Group(\"RingBufferArray\")\n    public Object readArray(final StateRingBufferArray ringBufferVarHandle, final ThreadPinningState t)\n    {\n        return ringBufferVarHandle.ringBufferVarHandle.get(64);\n    }\n\n    @Benchmark\n    @Group(\"RingBufferArray\")\n    public void writeArray(final StateRingBufferArray ringBufferVarHandle, final ThreadPinningState t)\n    {\n        ringBufferVarHandle.ringBufferVarHandle.publish(64);\n    }\n\n    public static void main(final String[] args) throws RunnerException\n    {\n        Options opt = new OptionsBuilder()\n                .include(RingBufferBenchmark.class.getSimpleName())\n                .build();\n        new Runner(opt).run();\n    }\n}\n"
  },
  {
    "path": "src/jmh/java/com/lmax/disruptor/RingBufferFalseSharingBenchmark.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.util.SimpleEvent;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Group;\nimport org.openjdk.jmh.annotations.Measurement;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.Warmup;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.RunnerException;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.concurrent.TimeUnit;\n\n/*\n * Based on false-sharing benchmark in open JDK\n * @see https://github.com/openjdk/jmh/blob/master/jmh-samples/src/main/java/org/openjdk/jmh/samples/JMHSample_22_FalseSharing.java\n *\n */\n\n@BenchmarkMode(Mode.Throughput)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)\n@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)\n@Fork(5)\npublic class RingBufferFalseSharingBenchmark\n{\n    /*\n     * We take advantage of the inheritance trick used in RingBuffer\n     * to create an object without the padding that occur after the fields.\n     *\n     * Java object layout using JDK15:\n     * com.lmax.disruptor.RingBufferFalseSharingBenchmark$HalfPaddedRingBufferWithNoisyNeighbour object internals:\n OFFSET  SIZE                           TYPE DESCRIPTION                                        VALUE\n      0    12                                (object header)                                    N/A\n     12     1                           byte RingBufferPad.p77                                  N/A\n     13     1                           byte RingBufferPad.p11                                  N/A\n     14     1                           byte RingBufferPad.p12                                  N/A\n     15     1                           byte RingBufferPad.p13                                  N/A\n     16     1                           byte RingBufferPad.p14                                  N/A\n     17     1                           byte RingBufferPad.p15                                  N/A\n     18     1                           byte RingBufferPad.p16                                  N/A\n     19     1                           byte RingBufferPad.p17                                  N/A\n     20     1                           byte RingBufferPad.p20                                  N/A\n     21     1                           byte RingBufferPad.p21                                  N/A\n     22     1                           byte RingBufferPad.p22                                  N/A\n     23     1                           byte RingBufferPad.p23                                  N/A\n     24     1                           byte RingBufferPad.p24                                  N/A\n     25     1                           byte RingBufferPad.p25                                  N/A\n     26     1                           byte RingBufferPad.p26                                  N/A\n     27     1                           byte RingBufferPad.p27                                  N/A\n     28     1                           byte RingBufferPad.p30                                  N/A\n     29     1                           byte RingBufferPad.p31                                  N/A\n     30     1                           byte RingBufferPad.p32                                  N/A\n     31     1                           byte RingBufferPad.p33                                  N/A\n     32     1                           byte RingBufferPad.p34                                  N/A\n     33     1                           byte RingBufferPad.p35                                  N/A\n     34     1                           byte RingBufferPad.p36                                  N/A\n     35     1                           byte RingBufferPad.p37                                  N/A\n     36     1                           byte RingBufferPad.p40                                  N/A\n     37     1                           byte RingBufferPad.p41                                  N/A\n     38     1                           byte RingBufferPad.p42                                  N/A\n     39     1                           byte RingBufferPad.p43                                  N/A\n     40     1                           byte RingBufferPad.p44                                  N/A\n     41     1                           byte RingBufferPad.p45                                  N/A\n     42     1                           byte RingBufferPad.p46                                  N/A\n     43     1                           byte RingBufferPad.p47                                  N/A\n     44     1                           byte RingBufferPad.p50                                  N/A\n     45     1                           byte RingBufferPad.p51                                  N/A\n     46     1                           byte RingBufferPad.p52                                  N/A\n     47     1                           byte RingBufferPad.p53                                  N/A\n     48     1                           byte RingBufferPad.p54                                  N/A\n     49     1                           byte RingBufferPad.p55                                  N/A\n     50     1                           byte RingBufferPad.p56                                  N/A\n     51     1                           byte RingBufferPad.p57                                  N/A\n     52     1                           byte RingBufferPad.p60                                  N/A\n     53     1                           byte RingBufferPad.p61                                  N/A\n     54     1                           byte RingBufferPad.p62                                  N/A\n     55     1                           byte RingBufferPad.p63                                  N/A\n     56     1                           byte RingBufferPad.p64                                  N/A\n     57     1                           byte RingBufferPad.p65                                  N/A\n     58     1                           byte RingBufferPad.p66                                  N/A\n     59     1                           byte RingBufferPad.p67                                  N/A\n     60     1                           byte RingBufferPad.p70                                  N/A\n     61     1                           byte RingBufferPad.p71                                  N/A\n     62     1                           byte RingBufferPad.p72                                  N/A\n     63     1                           byte RingBufferPad.p73                                  N/A\n     64     1                           byte RingBufferPad.p74                                  N/A\n     65     1                           byte RingBufferPad.p75                                  N/A\n     66     1                           byte RingBufferPad.p76                                  N/A\n     67     1                           byte RingBufferPad.p10                                  N/A\n     68     4                            int RingBufferFields.bufferSize                        N/A\n     72     8                           long RingBufferFields.indexMask                         N/A\n     80     4             java.lang.Object[] RingBufferFields.entries                           N/A\n     84     4   com.lmax.disruptor.Sequencer RingBufferFields.sequencer                         N/A\n     88     4                            int HalfPaddedRingBufferWithNoisyNeighbour.writeOnly   N/A\n     92     4                                (loss due to the next object alignment)\nInstance size: 96 bytes\nSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total\n\n     */\n    @State(Scope.Group)\n    public static class HalfPaddedRingBufferWithNoisyNeighbour extends RingBufferFields<SimpleEvent>\n    {\n        int writeOnly;\n\n        public HalfPaddedRingBufferWithNoisyNeighbour()\n        {\n            super(SimpleEvent::new, new SingleProducerSequencer(16, new BusySpinWaitStrategy()));\n        }\n    }\n\n    @Benchmark\n    @Group(\"halfpadded\")\n    public int reader(final HalfPaddedRingBufferWithNoisyNeighbour s)\n    {\n        return s.bufferSize;\n    }\n\n    @Benchmark\n    @Group(\"halfpadded\")\n    public void writer(final HalfPaddedRingBufferWithNoisyNeighbour s)\n    {\n        s.writeOnly++;\n    }\n\n    /*\n     * A fully padded RingBuffer using longs\n     */\n\n    @State(Scope.Group)\n    public static class PaddedRingBuffer extends RingBufferFields<SimpleEvent>\n        {\n            protected byte\n                p10, p11, p12, p13, p14, p15, p16, p17,\n                p20, p21, p22, p23, p24, p25, p26, p27,\n                p30, p31, p32, p33, p34, p35, p36, p37,\n                p40, p41, p42, p43, p44, p45, p46, p47,\n                p50, p51, p52, p53, p54, p55, p56, p57,\n                p60, p61, p62, p63, p64, p65, p66, p67,\n                p70, p71, p72, p73, p74, p75, p76, p77;\n\n        public PaddedRingBuffer()\n        {\n            super(SimpleEvent::new, new SingleProducerSequencer(16, new BusySpinWaitStrategy()));\n        }\n    }\n\n    /* Java object layout using JDK15:\n    com.lmax.disruptor.RingBufferFalseSharingBenchmark$PaddedRingBufferWithNoisyNeighbour object internals:\n OFFSET  SIZE                           TYPE DESCRIPTION                                    VALUE\n      0    12                                (object header)                                N/A\n     12     1                           byte RingBufferPad.p77                              N/A\n     13     1                           byte RingBufferPad.p11                              N/A\n     14     1                           byte RingBufferPad.p12                              N/A\n     15     1                           byte RingBufferPad.p13                              N/A\n     16     1                           byte RingBufferPad.p14                              N/A\n     17     1                           byte RingBufferPad.p15                              N/A\n     18     1                           byte RingBufferPad.p16                              N/A\n     19     1                           byte RingBufferPad.p17                              N/A\n     20     1                           byte RingBufferPad.p20                              N/A\n     21     1                           byte RingBufferPad.p21                              N/A\n     22     1                           byte RingBufferPad.p22                              N/A\n     23     1                           byte RingBufferPad.p23                              N/A\n     24     1                           byte RingBufferPad.p24                              N/A\n     25     1                           byte RingBufferPad.p25                              N/A\n     26     1                           byte RingBufferPad.p26                              N/A\n     27     1                           byte RingBufferPad.p27                              N/A\n     28     1                           byte RingBufferPad.p30                              N/A\n     29     1                           byte RingBufferPad.p31                              N/A\n     30     1                           byte RingBufferPad.p32                              N/A\n     31     1                           byte RingBufferPad.p33                              N/A\n     32     1                           byte RingBufferPad.p34                              N/A\n     33     1                           byte RingBufferPad.p35                              N/A\n     34     1                           byte RingBufferPad.p36                              N/A\n     35     1                           byte RingBufferPad.p37                              N/A\n     36     1                           byte RingBufferPad.p40                              N/A\n     37     1                           byte RingBufferPad.p41                              N/A\n     38     1                           byte RingBufferPad.p42                              N/A\n     39     1                           byte RingBufferPad.p43                              N/A\n     40     1                           byte RingBufferPad.p44                              N/A\n     41     1                           byte RingBufferPad.p45                              N/A\n     42     1                           byte RingBufferPad.p46                              N/A\n     43     1                           byte RingBufferPad.p47                              N/A\n     44     1                           byte RingBufferPad.p50                              N/A\n     45     1                           byte RingBufferPad.p51                              N/A\n     46     1                           byte RingBufferPad.p52                              N/A\n     47     1                           byte RingBufferPad.p53                              N/A\n     48     1                           byte RingBufferPad.p54                              N/A\n     49     1                           byte RingBufferPad.p55                              N/A\n     50     1                           byte RingBufferPad.p56                              N/A\n     51     1                           byte RingBufferPad.p57                              N/A\n     52     1                           byte RingBufferPad.p60                              N/A\n     53     1                           byte RingBufferPad.p61                              N/A\n     54     1                           byte RingBufferPad.p62                              N/A\n     55     1                           byte RingBufferPad.p63                              N/A\n     56     1                           byte RingBufferPad.p64                              N/A\n     57     1                           byte RingBufferPad.p65                              N/A\n     58     1                           byte RingBufferPad.p66                              N/A\n     59     1                           byte RingBufferPad.p67                              N/A\n     60     1                           byte RingBufferPad.p70                              N/A\n     61     1                           byte RingBufferPad.p71                              N/A\n     62     1                           byte RingBufferPad.p72                              N/A\n     63     1                           byte RingBufferPad.p73                              N/A\n     64     1                           byte RingBufferPad.p74                              N/A\n     65     1                           byte RingBufferPad.p75                              N/A\n     66     1                           byte RingBufferPad.p76                              N/A\n     67     1                           byte RingBufferPad.p10                              N/A\n     68     4                            int RingBufferFields.bufferSize                    N/A\n     72     8                           long RingBufferFields.indexMask                     N/A\n     80     4             java.lang.Object[] RingBufferFields.entries                       N/A\n     84     4   com.lmax.disruptor.Sequencer RingBufferFields.sequencer                     N/A\n     88     1                           byte PaddedRingBuffer.p77                           N/A\n     89     1                           byte PaddedRingBuffer.p11                           N/A\n     90     1                           byte PaddedRingBuffer.p12                           N/A\n     91     1                           byte PaddedRingBuffer.p13                           N/A\n     92     1                           byte PaddedRingBuffer.p14                           N/A\n     93     1                           byte PaddedRingBuffer.p15                           N/A\n     94     1                           byte PaddedRingBuffer.p16                           N/A\n     95     1                           byte PaddedRingBuffer.p17                           N/A\n     96     1                           byte PaddedRingBuffer.p20                           N/A\n     97     1                           byte PaddedRingBuffer.p21                           N/A\n     98     1                           byte PaddedRingBuffer.p22                           N/A\n     99     1                           byte PaddedRingBuffer.p23                           N/A\n    100     1                           byte PaddedRingBuffer.p24                           N/A\n    101     1                           byte PaddedRingBuffer.p25                           N/A\n    102     1                           byte PaddedRingBuffer.p26                           N/A\n    103     1                           byte PaddedRingBuffer.p27                           N/A\n    104     1                           byte PaddedRingBuffer.p30                           N/A\n    105     1                           byte PaddedRingBuffer.p31                           N/A\n    106     1                           byte PaddedRingBuffer.p32                           N/A\n    107     1                           byte PaddedRingBuffer.p33                           N/A\n    108     1                           byte PaddedRingBuffer.p34                           N/A\n    109     1                           byte PaddedRingBuffer.p35                           N/A\n    110     1                           byte PaddedRingBuffer.p36                           N/A\n    111     1                           byte PaddedRingBuffer.p37                           N/A\n    112     1                           byte PaddedRingBuffer.p40                           N/A\n    113     1                           byte PaddedRingBuffer.p41                           N/A\n    114     1                           byte PaddedRingBuffer.p42                           N/A\n    115     1                           byte PaddedRingBuffer.p43                           N/A\n    116     1                           byte PaddedRingBuffer.p44                           N/A\n    117     1                           byte PaddedRingBuffer.p45                           N/A\n    118     1                           byte PaddedRingBuffer.p46                           N/A\n    119     1                           byte PaddedRingBuffer.p47                           N/A\n    120     1                           byte PaddedRingBuffer.p50                           N/A\n    121     1                           byte PaddedRingBuffer.p51                           N/A\n    122     1                           byte PaddedRingBuffer.p52                           N/A\n    123     1                           byte PaddedRingBuffer.p53                           N/A\n    124     1                           byte PaddedRingBuffer.p54                           N/A\n    125     1                           byte PaddedRingBuffer.p55                           N/A\n    126     1                           byte PaddedRingBuffer.p56                           N/A\n    127     1                           byte PaddedRingBuffer.p57                           N/A\n    128     1                           byte PaddedRingBuffer.p60                           N/A\n    129     1                           byte PaddedRingBuffer.p61                           N/A\n    130     1                           byte PaddedRingBuffer.p62                           N/A\n    131     1                           byte PaddedRingBuffer.p63                           N/A\n    132     1                           byte PaddedRingBuffer.p64                           N/A\n    133     1                           byte PaddedRingBuffer.p65                           N/A\n    134     1                           byte PaddedRingBuffer.p66                           N/A\n    135     1                           byte PaddedRingBuffer.p67                           N/A\n    136     1                           byte PaddedRingBuffer.p70                           N/A\n    137     1                           byte PaddedRingBuffer.p71                           N/A\n    138     1                           byte PaddedRingBuffer.p72                           N/A\n    139     1                           byte PaddedRingBuffer.p73                           N/A\n    140     1                           byte PaddedRingBuffer.p74                           N/A\n    141     1                           byte PaddedRingBuffer.p75                           N/A\n    142     1                           byte PaddedRingBuffer.p76                           N/A\n    143     1                           byte PaddedRingBuffer.p10                           N/A\n    144     4                            int PaddedRingBufferWithNoisyNeighbour.writeOnly   N/A\n    148     4                                (loss due to the next object alignment)\nInstance size: 152 bytes\nSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total\n     */\n    @State(Scope.Group)\n    public static class PaddedRingBufferWithNoisyNeighbour extends PaddedRingBuffer\n    {\n        int writeOnly;\n    }\n\n    @Benchmark\n    @Group(\"padded\")\n    public int reader(final PaddedRingBufferWithNoisyNeighbour s)\n    {\n        return s.bufferSize;\n    }\n\n    @Benchmark\n    @Group(\"padded\")\n    public void writer(final PaddedRingBufferWithNoisyNeighbour s)\n    {\n        s.writeOnly++;\n    }\n\n    public static void main(final String[] args) throws RunnerException\n    {\n        Options opt = new OptionsBuilder()\n            .include(RingBufferFalseSharingBenchmark.class.getSimpleName())\n            .threads(Runtime.getRuntime().availableProcessors())\n            .build();\n\n        new Runner(opt).run();\n    }\n\n}"
  },
  {
    "path": "src/jmh/java/com/lmax/disruptor/SequenceBenchmark.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.alternatives.SequenceDoublePadded;\nimport com.lmax.disruptor.alternatives.SequenceUnsafe;\nimport com.lmax.disruptor.alternatives.SequenceVarHandle;\nimport com.lmax.disruptor.alternatives.SequenceVarHandleArray;\nimport com.lmax.disruptor.alternatives.SequenceVarHandleBarrier;\nimport net.openhft.affinity.Affinity;\nimport net.openhft.affinity.AffinityLock;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Group;\nimport org.openjdk.jmh.annotations.Measurement;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.TearDown;\nimport org.openjdk.jmh.annotations.Threads;\nimport org.openjdk.jmh.annotations.Warmup;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.RunnerException;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.stream.Collectors;\n\nimport static java.util.function.Predicate.not;\n\n@SuppressWarnings(\"ALL\")\n@BenchmarkMode(Mode.Throughput)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@Warmup(iterations = 5, time = 1)\n@Measurement(iterations = 5, time = 1)\n@Fork(2)\n@Threads(1)\npublic class SequenceBenchmark\n{\n    // To run this on a tuned system with benchmark threads pinned to isolated cpus:\n    // Run the JMH process with an env var defining the isolated cpu list, e.g. ISOLATED_CPUS=38,40,42,44,46,48 java -jar disruptor-jmh.jar\n    private static final List<Integer> ISOLATED_CPUS = Arrays.stream(System.getenv().getOrDefault(\"ISOLATED_CPUS\", \"\").split(\",\"))\n            .map(String::trim)\n            .filter(not(String::isBlank))\n            .map(Integer::valueOf)\n            .collect(Collectors.toList());\n\n    private static final AtomicInteger THREAD_COUNTER = new AtomicInteger();\n\n    @State(Scope.Thread)\n    public static class ThreadPinningState\n    {\n        int threadId = THREAD_COUNTER.getAndIncrement();\n        private AffinityLock affinityLock;\n\n        @Setup\n        public void setup()\n        {\n            if (ISOLATED_CPUS.size() > 0)\n            {\n                if (threadId > ISOLATED_CPUS.size())\n                {\n                    throw new IllegalArgumentException(\n                            String.format(\"Benchmark uses at least %d threads, only defined %d isolated cpus\",\n                                    threadId,\n                                    ISOLATED_CPUS.size()\n                            ));\n                }\n\n                final Integer cpuId = ISOLATED_CPUS.get(threadId);\n                affinityLock = AffinityLock.acquireLock(cpuId);\n                System.out.printf(\"Attempted to set thread affinity for %s to %d, success = %b%n\",\n                        Thread.currentThread().getName(),\n                        cpuId,\n                        affinityLock.isAllocated()\n                );\n            }\n            else\n            {\n                System.err.printf(\"ISOLATED_CPUS environment variable not defined, running thread %s (id=%d) on scheduler-defined CPU:%d%n \",\n                        Thread.currentThread().getName(),\n                        threadId,\n                        Affinity.getCpu());\n            }\n        }\n\n        @TearDown\n        public void teardown()\n        {\n            if (ISOLATED_CPUS.size() > 0)\n            {\n                affinityLock.release();\n            }\n        }\n    }\n\n    /*\n     * APPROACH 1: AtomicLong\n     *\n     * Thread safe? Check. Atomic updates? Check.\n     */\n    @State(Scope.Group)\n    public static class StateAtomic\n    {\n        AtomicLong value1 = new AtomicLong(0);\n        AtomicLong value2 = new AtomicLong(0);\n    }\n\n    @Benchmark\n    @Group(\"AtomicLong\")\n    public long read1(final StateAtomic s, final ThreadPinningState t)\n    {\n        return s.value1.get();\n    }\n\n    @Benchmark\n    @Group(\"AtomicLong\")\n    public long read2(final StateAtomic s, final ThreadPinningState t)\n    {\n        return s.value2.get();\n    }\n\n    @Benchmark\n    @Group(\"AtomicLong\")\n    public void setValue1Opaque(final StateAtomic s, final ThreadPinningState t)\n    {\n        // Put Long Opaque\n        s.value1.setOpaque(1234L);\n    }\n\n    @Benchmark\n    @Group(\"AtomicLong\")\n    public void setValue1Volatile(final StateAtomic s, final ThreadPinningState t)\n    {\n        // Put Long Volatile\n        s.value1.set(5678L);\n    }\n\n    @Benchmark\n    @Group(\"AtomicLong\")\n    public long incrementValue2(final StateAtomic s, final ThreadPinningState t)\n    {\n        return s.value2.getAndIncrement();\n    }\n\n    /*\n     * APPROACH 2: com.lmax.disruptor.Sequence (as of disruptor v3.4.2)\n     *\n     * A lot like AtomicLong, but with some padding to avoid false sharing.\n     * This uses UNSAFE to give us more control over the memory model of the field, we don't always need full volatile\n     * guarantees and we need to use compareAndSwap to be atomic.\n     */\n    @State(Scope.Group)\n    public static class StateSequenceUnsafe\n    {\n        SequenceUnsafe value1 = new SequenceUnsafe(0);\n        SequenceUnsafe value2 = new SequenceUnsafe(0);\n    }\n\n    @Benchmark\n    @Group(\"SequenceUnsafe\")\n    public long read1(final StateSequenceUnsafe s, final ThreadPinningState t)\n    {\n        return s.value1.get();\n    }\n\n    @Benchmark\n    @Group(\"SequenceUnsafe\")\n    public long read2(final StateSequenceUnsafe s, final ThreadPinningState t)\n    {\n        return s.value2.get();\n    }\n\n    @Benchmark\n    @Group(\"SequenceUnsafe\")\n    public void setValue1(final StateSequenceUnsafe s, final ThreadPinningState t)\n    {\n        // Put Ordered Long\n        s.value1.set(1234L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceUnsafe\")\n    public void setValue1Volatile(final StateSequenceUnsafe s, final ThreadPinningState t)\n    {\n        // Put Long Volatile\n        s.value1.setVolatile(5678L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceUnsafe\")\n    public long incrementValue2(final StateSequenceUnsafe s, final ThreadPinningState t)\n    {\n        return s.value2.incrementAndGet();\n    }\n\n    /*\n     * APPROACH 2.5: com.lmax.disruptor.alternatives.SequenceDoublePadded\n     *\n     * This is identical to the Sequence from Disruptor 3.4.2 but with double the amount of padding.\n     * https://github.com/LMAX-Exchange/disruptor/issues/231 raised the point of Intel CPUs optionally (on by default I\n     * believe) prefetching 2 cache lines.\n     *\n     * This benchmark should show if there is any difference in performance having extra padding when compared to the\n     * regular Sequence benchmark.\n     */\n    @State(Scope.Group)\n    public static class StateSequenceDoublePadded\n    {\n        SequenceDoublePadded value1 = new SequenceDoublePadded(0);\n        SequenceDoublePadded value2 = new SequenceDoublePadded(0);\n    }\n\n    @Benchmark\n    @Group(\"SequenceDoublePadded\")\n    public long read1(final StateSequenceDoublePadded s, final ThreadPinningState t)\n    {\n        return s.value1.get();\n    }\n\n    @Benchmark\n    @Group(\"SequenceDoublePadded\")\n    public long read2(final StateSequenceDoublePadded s, final ThreadPinningState t)\n    {\n        return s.value2.get();\n    }\n\n    @Benchmark\n    @Group(\"SequenceDoublePadded\")\n    public void setValue1(final StateSequenceDoublePadded s, final ThreadPinningState t)\n    {\n        // Put Ordered Long\n        s.value1.set(1234L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceDoublePadded\")\n    public void setValue1Volatile(final StateSequenceDoublePadded s, final ThreadPinningState t)\n    {\n        // Put Long Volatile\n        s.value1.setVolatile(5678L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceDoublePadded\")\n    public long incrementValue2(final StateSequenceDoublePadded s, final ThreadPinningState t)\n    {\n        return s.value2.incrementAndGet();\n    }\n\n    /*\n     * APPROACH 3: com.lmax.disruptor.alternatives.SequenceVarHandle\n     *\n     * An updated version of com.lmax.disruptor.Sequence but using VarHandle instead of UNSAFE to get memory ordering.\n     * This is probably the way we should go for version Disruptor 4.0\n     */\n    @State(Scope.Group)\n    public static class StateSequenceVarHandle\n    {\n        SequenceVarHandle value1 = new SequenceVarHandle(0);\n        SequenceVarHandle value2 = new SequenceVarHandle(0);\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandle\")\n    public long read1(final StateSequenceVarHandle s, final ThreadPinningState t)\n    {\n        return s.value1.get();\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandle\")\n    public long read2(final StateSequenceVarHandle s, final ThreadPinningState t)\n    {\n        return s.value2.get();\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandle\")\n    public void setValue1(final StateSequenceVarHandle s, final ThreadPinningState t)\n    {\n        // Put Ordered Long\n        s.value1.set(1234L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandle\")\n    public void setValue1Volatile(final StateSequenceVarHandle s, final ThreadPinningState t)\n    {\n        // Put Long Volatile\n        s.value1.setVolatile(5678L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandle\")\n    public long incrementValue2(final StateSequenceVarHandle s, final ThreadPinningState t)\n    {\n        return s.value2.incrementAndGet();\n    }\n\n    /*\n     * APPROACH 3.5: com.lmax.disruptor.alternatives.SequenceVarHandleBarrier\n     *\n     * Much like the VarHandle version but with manual memory barriers used.\n     * We think this might cut down on some boxing and maybe gives a little more flexibility.\n     */\n    @State(Scope.Group)\n    public static class StateSequenceVarHandleBarrier\n    {\n        SequenceVarHandleBarrier value1 = new SequenceVarHandleBarrier(0);\n        SequenceVarHandleBarrier value2 = new SequenceVarHandleBarrier(0);\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandleBarrier\")\n    public long read1(final StateSequenceVarHandleBarrier s, final ThreadPinningState t)\n    {\n        return s.value1.get();\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandleBarrier\")\n    public long read2(final StateSequenceVarHandleBarrier s, final ThreadPinningState t)\n    {\n        return s.value2.get();\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandleBarrier\")\n    public void setValue1(final StateSequenceVarHandleBarrier s, final ThreadPinningState t)\n    {\n        // Put Ordered Long\n        s.value1.set(1234L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandleBarrier\")\n    public void setValue1Volatile(final StateSequenceVarHandleBarrier s, final ThreadPinningState t)\n    {\n        // Put Long Volatile\n        s.value1.setVolatile(5678L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandleBarrier\")\n    public long incrementValue2(final StateSequenceVarHandleBarrier s, final ThreadPinningState t)\n    {\n        return s.value2.incrementAndGet();\n    }\n\n    /*\n     * APPROACH 4: com.lmax.disruptor.alternatives.SequenceVarHandleArray\n     *\n     * Similar to the SequenceVarHandle but instead of using class hierarchy for padding, using a long array.\n     * This seemed like a good idea but suffers from array bounds checking slowing down all the operations.\n     * This method probably isn't a good way to go, but kept here as a warning to others who think this is a good way to\n     * do cache-line padding.\n     */\n    @State(Scope.Group)\n    public static class StateSequenceVarHandleArray\n    {\n        SequenceVarHandleArray value1 = new SequenceVarHandleArray(0);\n        SequenceVarHandleArray value2 = new SequenceVarHandleArray(0);\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandleArray\")\n    public long read1(final StateSequenceVarHandleArray s, final ThreadPinningState t)\n    {\n        return s.value1.get();\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandleArray\")\n    public long read2(final StateSequenceVarHandleArray s, final ThreadPinningState t)\n    {\n        return s.value2.get();\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandleArray\")\n    public void setValue1(final StateSequenceVarHandleArray s, final ThreadPinningState t)\n    {\n        // Put Ordered Long\n        s.value1.set(1234L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandleArray\")\n    public void setValue1Volatile(final StateSequenceVarHandleArray s, final ThreadPinningState t)\n    {\n        // Put Long Volatile\n        s.value1.setVolatile(5678L);\n    }\n\n    @Benchmark\n    @Group(\"SequenceVarHandleArray\")\n    public long incrementValue2(final StateSequenceVarHandleArray s, final ThreadPinningState t)\n    {\n        return s.value2.incrementAndGet();\n    }\n\n    public static void main(final String[] args) throws RunnerException\n    {\n        Options opt = new OptionsBuilder()\n                .include(SequenceBenchmark.class.getSimpleName())\n                .build();\n        new Runner(opt).run();\n    }\n}\n"
  },
  {
    "path": "src/jmh/java/com/lmax/disruptor/SingleProducerSingleConsumer.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.dsl.ProducerType;\nimport com.lmax.disruptor.util.Constants;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport com.lmax.disruptor.util.SimpleEvent;\nimport com.lmax.disruptor.util.SimpleEventHandler;\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.annotations.BenchmarkMode;\nimport org.openjdk.jmh.annotations.Fork;\nimport org.openjdk.jmh.annotations.Mode;\nimport org.openjdk.jmh.annotations.OutputTimeUnit;\nimport org.openjdk.jmh.annotations.Scope;\nimport org.openjdk.jmh.annotations.Setup;\nimport org.openjdk.jmh.annotations.State;\nimport org.openjdk.jmh.annotations.TearDown;\nimport org.openjdk.jmh.infra.Blackhole;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.RunnerException;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.concurrent.TimeUnit;\n\n@BenchmarkMode(Mode.AverageTime)\n@OutputTimeUnit(TimeUnit.NANOSECONDS)\n@State(Scope.Thread)\n@Fork(1)\npublic class SingleProducerSingleConsumer\n{\n    private RingBuffer<SimpleEvent> ringBuffer;\n    private Disruptor<SimpleEvent> disruptor;\n\n    @Setup\n    public void setup(final Blackhole bh)\n    {\n        disruptor = new Disruptor<>(SimpleEvent::new,\n                Constants.RINGBUFFER_SIZE,\n                DaemonThreadFactory.INSTANCE,\n                ProducerType.SINGLE,\n                new BusySpinWaitStrategy());\n\n        disruptor.handleEventsWith(new SimpleEventHandler(bh));\n\n        ringBuffer = disruptor.start();\n    }\n\n    @Benchmark\n    public void producing()\n    {\n        long sequence = ringBuffer.next();\n        SimpleEvent simpleEvent = ringBuffer.get(sequence);\n        simpleEvent.setValue(0);\n        ringBuffer.publish(sequence);\n    }\n\n    @TearDown\n    public void tearDown()\n    {\n        disruptor.shutdown();\n    }\n\n    public static void main(final String[] args) throws RunnerException\n    {\n        Options opt = new OptionsBuilder()\n                .include(SingleProducerSingleConsumer.class.getSimpleName())\n                .forks(1)\n                .build();\n        new Runner(opt).run();\n    }\n}\n"
  },
  {
    "path": "src/jmh/java/com/lmax/disruptor/util/Constants.java",
    "content": "package com.lmax.disruptor.util;\n\npublic class Constants\n{\n    public static final int RINGBUFFER_SIZE = 1 << 20;\n    public static final int ITERATIONS = 1_000_000;\n}\n"
  },
  {
    "path": "src/jmh/java/com/lmax/disruptor/util/SimpleEvent.java",
    "content": "package com.lmax.disruptor.util;\n\npublic class SimpleEvent\n{\n    private long value = Long.MIN_VALUE;\n\n    public long getValue()\n    {\n        return value;\n    }\n\n    public void setValue(final long value)\n    {\n        this.value = value;\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"SimpleEvent{\" +\n                \"value=\" + value +\n                '}';\n    }\n}\n"
  },
  {
    "path": "src/jmh/java/com/lmax/disruptor/util/SimpleEventHandler.java",
    "content": "package com.lmax.disruptor.util;\n\nimport com.lmax.disruptor.EventHandler;\nimport org.openjdk.jmh.infra.Blackhole;\n\npublic class SimpleEventHandler implements EventHandler<SimpleEvent>\n{\n    private final Blackhole bh;\n\n    public SimpleEventHandler(final Blackhole bh)\n    {\n        this.bh = bh;\n    }\n\n    @Override\n    public void onEvent(final SimpleEvent event, final long sequence, final boolean endOfBatch)\n    {\n        bh.consume(event);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/AbstractSequencer.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.util.Util;\n\nimport java.util.Arrays;\nimport java.util.concurrent.atomic.AtomicReferenceFieldUpdater;\n\n/**\n * Base class for the various sequencer types (single/multi).  Provides\n * common functionality like the management of gating sequences (add/remove) and\n * ownership of the current cursor.\n */\npublic abstract class AbstractSequencer implements Sequencer\n{\n    private static final AtomicReferenceFieldUpdater<AbstractSequencer, Sequence[]> SEQUENCE_UPDATER =\n        AtomicReferenceFieldUpdater.newUpdater(AbstractSequencer.class, Sequence[].class, \"gatingSequences\");\n\n    protected final int bufferSize;\n    protected final WaitStrategy waitStrategy;\n    protected final Sequence cursor = new Sequence(Sequencer.INITIAL_CURSOR_VALUE);\n    protected volatile Sequence[] gatingSequences = new Sequence[0];\n\n    /**\n     * Create with the specified buffer size and wait strategy.\n     *\n     * @param bufferSize   The total number of entries, must be a positive power of 2.\n     * @param waitStrategy The wait strategy used by this sequencer\n     */\n    public AbstractSequencer(final int bufferSize, final WaitStrategy waitStrategy)\n    {\n        if (bufferSize < 1)\n        {\n            throw new IllegalArgumentException(\"bufferSize must not be less than 1\");\n        }\n        if (Integer.bitCount(bufferSize) != 1)\n        {\n            throw new IllegalArgumentException(\"bufferSize must be a power of 2\");\n        }\n\n        this.bufferSize = bufferSize;\n        this.waitStrategy = waitStrategy;\n    }\n\n    /**\n     * @see Sequencer#getCursor()\n     */\n    @Override\n    public final long getCursor()\n    {\n        return cursor.get();\n    }\n\n    /**\n     * @see Sequencer#getBufferSize()\n     */\n    @Override\n    public final int getBufferSize()\n    {\n        return bufferSize;\n    }\n\n    /**\n     * @see Sequencer#addGatingSequences(Sequence...)\n     */\n    @Override\n    public final void addGatingSequences(final Sequence... gatingSequences)\n    {\n        SequenceGroups.addSequences(this, SEQUENCE_UPDATER, this, gatingSequences);\n    }\n\n    /**\n     * @see Sequencer#removeGatingSequence(Sequence)\n     */\n    @Override\n    public boolean removeGatingSequence(final Sequence sequence)\n    {\n        return SequenceGroups.removeSequence(this, SEQUENCE_UPDATER, sequence);\n    }\n\n    /**\n     * @see Sequencer#getMinimumSequence()\n     */\n    @Override\n    public long getMinimumSequence()\n    {\n        return Util.getMinimumSequence(gatingSequences, cursor.get());\n    }\n\n    /**\n     * @see Sequencer#newBarrier(Sequence...)\n     */\n    @Override\n    public SequenceBarrier newBarrier(final Sequence... sequencesToTrack)\n    {\n        return new ProcessingSequenceBarrier(this, waitStrategy, cursor, sequencesToTrack);\n    }\n\n    /**\n     * Creates an event poller for this sequence that will use the supplied data provider and\n     * gating sequences.\n     *\n     * @param dataProvider    The data source for users of this event poller\n     * @param gatingSequences Sequence to be gated on.\n     * @return A poller that will gate on this ring buffer and the supplied sequences.\n     */\n    @Override\n    public <T> EventPoller<T> newPoller(final DataProvider<T> dataProvider, final Sequence... gatingSequences)\n    {\n        return EventPoller.newInstance(dataProvider, this, new Sequence(), cursor, gatingSequences);\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"AbstractSequencer{\" +\n            \"waitStrategy=\" + waitStrategy +\n            \", cursor=\" + cursor +\n            \", gatingSequences=\" + Arrays.toString(gatingSequences) +\n            '}';\n    }\n}"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/AggregateEventHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * An aggregate collection of {@link EventHandler}s that get called in sequence for each event.\n *\n * @param <T> event implementation storing the data for sharing during exchange or parallel coordination of an event.\n */\npublic final class AggregateEventHandler<T>\n    implements EventHandler<T>\n{\n    private final EventHandler<T>[] eventHandlers;\n\n    /**\n     * Construct an aggregate collection of {@link EventHandler}s to be called in sequence.\n     *\n     * @param eventHandlers to be called in sequence.\n     */\n    @SafeVarargs\n    public AggregateEventHandler(final EventHandler<T>... eventHandlers)\n    {\n        this.eventHandlers = eventHandlers;\n    }\n\n    @Override\n    public void onEvent(final T event, final long sequence, final boolean endOfBatch)\n        throws Exception\n    {\n        for (final EventHandler<T> eventHandler : eventHandlers)\n        {\n            eventHandler.onEvent(event, sequence, endOfBatch);\n        }\n    }\n\n    @Override\n    public void onStart()\n    {\n        for (final EventHandler<T> eventHandler : eventHandlers)\n        {\n            eventHandler.onStart();\n        }\n    }\n\n    @Override\n    public void onShutdown()\n    {\n        for (final EventHandler<T> eventHandler : eventHandlers)\n        {\n            eventHandler.onShutdown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/AlertException.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Used to alert {@link EventProcessor}s waiting at a {@link SequenceBarrier} of status changes.\n *\n * <p>It does not fill in a stack trace for performance reasons.\n */\n@SuppressWarnings({\"serial\", \"lgtm[java/non-sync-override]\"})\npublic final class AlertException extends Exception\n{\n    /**\n     * Pre-allocated exception to avoid garbage generation.\n     */\n    public static final AlertException INSTANCE = new AlertException();\n\n    /**\n     * Private constructor so only a single instance exists.\n     */\n    private AlertException()\n    {\n    }\n\n    /**\n     * Overridden so the stack trace is not filled in for this exception for performance reasons.\n     *\n     * @return this instance.\n     */\n    @Override\n    public Throwable fillInStackTrace()\n    {\n        return this;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/BatchEventProcessor.java",
    "content": "/*\n * Copyright 2022 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static com.lmax.disruptor.RewindAction.REWIND;\nimport static java.lang.Math.min;\n\n\n/**\n * Convenience class for handling the batching semantics of consuming entries from a {@link RingBuffer}\n * and delegating the available events to an {@link EventHandler}.\n *\n * @param <T> event implementation storing the data for sharing during exchange or parallel coordination of an event.\n */\npublic final class BatchEventProcessor<T>\n        implements EventProcessor\n{\n    private static final int IDLE = 0;\n    private static final int HALTED = IDLE + 1;\n    private static final int RUNNING = HALTED + 1;\n\n    private final AtomicInteger running = new AtomicInteger(IDLE);\n    private ExceptionHandler<? super T> exceptionHandler;\n    private final DataProvider<T> dataProvider;\n    private final SequenceBarrier sequenceBarrier;\n    private final EventHandlerBase<? super T> eventHandler;\n    private final int batchLimitOffset;\n    private final Sequence sequence = new Sequence(Sequencer.INITIAL_CURSOR_VALUE);\n    private final RewindHandler rewindHandler;\n    private int retriesAttempted = 0;\n\n    BatchEventProcessor(\n            final DataProvider<T> dataProvider,\n            final SequenceBarrier sequenceBarrier,\n            final EventHandlerBase<? super T> eventHandler,\n            final int maxBatchSize,\n            final BatchRewindStrategy batchRewindStrategy\n    )\n    {\n        this.dataProvider = dataProvider;\n        this.sequenceBarrier = sequenceBarrier;\n        this.eventHandler = eventHandler;\n\n        if (maxBatchSize < 1)\n        {\n            throw new IllegalArgumentException(\"maxBatchSize must be greater than 0\");\n        }\n        this.batchLimitOffset = maxBatchSize - 1;\n\n        this.rewindHandler = eventHandler instanceof RewindableEventHandler\n                ? new TryRewindHandler(batchRewindStrategy)\n                : new NoRewindHandler();\n    }\n\n    @Override\n    public Sequence getSequence()\n    {\n        return sequence;\n    }\n\n    @Override\n    public void halt()\n    {\n        running.set(HALTED);\n        sequenceBarrier.alert();\n    }\n\n    @Override\n    public boolean isRunning()\n    {\n        return running.get() != IDLE;\n    }\n\n    /**\n     * Set a new {@link ExceptionHandler} for handling exceptions propagated out of the {@link BatchEventProcessor}.\n     *\n     * @param exceptionHandler to replace the existing exceptionHandler.\n     */\n    public void setExceptionHandler(final ExceptionHandler<? super T> exceptionHandler)\n    {\n        if (null == exceptionHandler)\n        {\n            throw new NullPointerException();\n        }\n\n        this.exceptionHandler = exceptionHandler;\n    }\n\n    /**\n     * It is ok to have another thread rerun this method after a halt().\n     *\n     * @throws IllegalStateException if this object instance is already running in a thread\n     */\n    @Override\n    public void run()\n    {\n        int witnessValue = running.compareAndExchange(IDLE, RUNNING);\n        if (witnessValue == IDLE) // Successful CAS\n        {\n            sequenceBarrier.clearAlert();\n\n            notifyStart();\n            try\n            {\n                if (running.get() == RUNNING)\n                {\n                    processEvents();\n                }\n            }\n            finally\n            {\n                notifyShutdown();\n                running.set(IDLE);\n            }\n        }\n        else\n        {\n            if (witnessValue == RUNNING)\n            {\n                throw new IllegalStateException(\"Thread is already running\");\n            }\n            else\n            {\n                earlyExit();\n            }\n        }\n    }\n\n    private void processEvents()\n    {\n        T event = null;\n        long nextSequence = sequence.get() + 1L;\n\n        while (true)\n        {\n            final long startOfBatchSequence = nextSequence;\n            try\n            {\n                try\n                {\n                    final long availableSequence = sequenceBarrier.waitFor(nextSequence);\n                    final long endOfBatchSequence = min(nextSequence + batchLimitOffset, availableSequence);\n\n                    if (nextSequence <= endOfBatchSequence)\n                    {\n                        eventHandler.onBatchStart(endOfBatchSequence - nextSequence + 1, availableSequence - nextSequence + 1);\n                    }\n\n                    while (nextSequence <= endOfBatchSequence)\n                    {\n                        event = dataProvider.get(nextSequence);\n                        eventHandler.onEvent(event, nextSequence, nextSequence == endOfBatchSequence);\n                        nextSequence++;\n                    }\n\n                    retriesAttempted = 0;\n\n                    sequence.set(endOfBatchSequence);\n                }\n                catch (final RewindableException e)\n                {\n                    nextSequence = rewindHandler.attemptRewindGetNextSequence(e, startOfBatchSequence);\n                }\n            }\n            catch (final TimeoutException e)\n            {\n                notifyTimeout(sequence.get());\n            }\n            catch (final AlertException ex)\n            {\n                if (running.get() != RUNNING)\n                {\n                    break;\n                }\n            }\n            catch (final Throwable ex)\n            {\n                handleEventException(ex, nextSequence, event);\n                sequence.set(nextSequence);\n                nextSequence++;\n            }\n        }\n    }\n\n    private void earlyExit()\n    {\n        notifyStart();\n        notifyShutdown();\n    }\n\n    private void notifyTimeout(final long availableSequence)\n    {\n        try\n        {\n            eventHandler.onTimeout(availableSequence);\n        }\n        catch (Throwable e)\n        {\n            handleEventException(e, availableSequence, null);\n        }\n    }\n\n    /**\n     * Notifies the EventHandler when this processor is starting up.\n     */\n    private void notifyStart()\n    {\n        try\n        {\n            eventHandler.onStart();\n        }\n        catch (final Throwable ex)\n        {\n            handleOnStartException(ex);\n        }\n    }\n\n    /**\n     * Notifies the EventHandler immediately prior to this processor shutting down.\n     */\n    private void notifyShutdown()\n    {\n        try\n        {\n            eventHandler.onShutdown();\n        }\n        catch (final Throwable ex)\n        {\n            handleOnShutdownException(ex);\n        }\n    }\n\n    /**\n     * Delegate to {@link ExceptionHandler#handleEventException(Throwable, long, Object)} on the delegate or\n     * the default {@link ExceptionHandler} if one has not been configured.\n     */\n    private void handleEventException(final Throwable ex, final long sequence, final T event)\n    {\n        getExceptionHandler().handleEventException(ex, sequence, event);\n    }\n\n    /**\n     * Delegate to {@link ExceptionHandler#handleOnStartException(Throwable)} on the delegate or\n     * the default {@link ExceptionHandler} if one has not been configured.\n     */\n    private void handleOnStartException(final Throwable ex)\n    {\n        getExceptionHandler().handleOnStartException(ex);\n    }\n\n    /**\n     * Delegate to {@link ExceptionHandler#handleOnShutdownException(Throwable)} on the delegate or\n     * the default {@link ExceptionHandler} if one has not been configured.\n     */\n    private void handleOnShutdownException(final Throwable ex)\n    {\n        getExceptionHandler().handleOnShutdownException(ex);\n    }\n\n    private ExceptionHandler<? super T> getExceptionHandler()\n    {\n        ExceptionHandler<? super T> handler = exceptionHandler;\n        return handler == null ? ExceptionHandlers.defaultHandler() : handler;\n    }\n\n    private class TryRewindHandler implements RewindHandler\n    {\n        private final BatchRewindStrategy batchRewindStrategy;\n\n        TryRewindHandler(final BatchRewindStrategy batchRewindStrategy)\n        {\n            this.batchRewindStrategy = batchRewindStrategy;\n        }\n\n        @Override\n        public long attemptRewindGetNextSequence(final RewindableException e, final long startOfBatchSequence) throws RewindableException\n        {\n            if (batchRewindStrategy.handleRewindException(e, ++retriesAttempted) == REWIND)\n            {\n                return startOfBatchSequence;\n            }\n            else\n            {\n                retriesAttempted = 0;\n                throw e;\n            }\n        }\n    }\n\n    private static class NoRewindHandler implements RewindHandler\n    {\n        @Override\n        public long attemptRewindGetNextSequence(final RewindableException e, final long startOfBatchSequence)\n        {\n            throw new UnsupportedOperationException(\"Rewindable Exception thrown from a non-rewindable event handler\", e);\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/BatchEventProcessorBuilder.java",
    "content": "/*\n * Copyright 2023 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lmax.disruptor;\n\npublic final class BatchEventProcessorBuilder\n{\n    private int maxBatchSize = Integer.MAX_VALUE;\n\n    /**\n     * Set the maximum number of events that will be processed in a batch before updating the sequence.\n     *\n     * @param maxBatchSize max number of events to process in one batch.\n     * @return The builder\n     */\n    public BatchEventProcessorBuilder setMaxBatchSize(final int maxBatchSize)\n    {\n        this.maxBatchSize = maxBatchSize;\n        return this;\n    }\n\n    /**\n     * Construct a {@link EventProcessor} that will automatically track the progress by updating its sequence when\n     * the {@link EventHandler#onEvent(Object, long, boolean)} method returns.\n     *\n     * <p>The created {@link BatchEventProcessor} will not support batch rewind,\n     * but {@link EventHandler#setSequenceCallback(Sequence)} will be supported.\n     *\n     * @param dataProvider    to which events are published.\n     * @param sequenceBarrier on which it is waiting.\n     * @param eventHandler    is the delegate to which events are dispatched.\n     * @param <T>             event implementation storing the data for sharing during exchange or parallel coordination of an event.\n     * @return the BatchEventProcessor\n     */\n    public <T> BatchEventProcessor<T> build(\n            final DataProvider<T> dataProvider,\n            final SequenceBarrier sequenceBarrier,\n            final EventHandler<? super T> eventHandler)\n    {\n        final BatchEventProcessor<T> processor = new BatchEventProcessor<>(\n                dataProvider, sequenceBarrier, eventHandler, maxBatchSize, null\n        );\n        eventHandler.setSequenceCallback(processor.getSequence());\n\n        return processor;\n    }\n\n    /**\n     * Construct a {@link EventProcessor} that will automatically track the progress by updating its sequence when\n     * the {@link EventHandler#onEvent(Object, long, boolean)} method returns.\n     *\n     * @param dataProvider           to which events are published.\n     * @param sequenceBarrier        on which it is waiting.\n     * @param rewindableEventHandler is the delegate to which events are dispatched.\n     * @param batchRewindStrategy    a {@link BatchRewindStrategy} for customizing how to handle a {@link RewindableException}.\n     * @param <T>                    event implementation storing the data for sharing during exchange or parallel coordination of an event.\n     * @return the BatchEventProcessor\n     */\n    public <T> BatchEventProcessor<T> build(\n            final DataProvider<T> dataProvider,\n            final SequenceBarrier sequenceBarrier,\n            final RewindableEventHandler<? super T> rewindableEventHandler,\n            final BatchRewindStrategy batchRewindStrategy)\n    {\n        if (null == batchRewindStrategy)\n        {\n            throw new NullPointerException(\"batchRewindStrategy cannot be null when building a BatchEventProcessor\");\n        }\n\n        return new BatchEventProcessor<>(\n                dataProvider, sequenceBarrier, rewindableEventHandler, maxBatchSize, batchRewindStrategy\n        );\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/BatchRewindStrategy.java",
    "content": "package com.lmax.disruptor;\n\n/**\n * Strategy for handling a rewindableException when processing an event.\n */\npublic interface BatchRewindStrategy\n{\n\n    /**\n     * When a {@link RewindableException} is thrown, this will be called.\n     *\n     * @param e       the exception that propagated from the {@link EventHandler}.\n     * @param attempts how many attempts there have been for the batch\n     * @return the decision of whether to rewind the batch or throw the exception\n     */\n    RewindAction handleRewindException(RewindableException e, int attempts);\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/BlockingWaitStrategy.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Blocking strategy that uses a lock and condition variable for {@link EventProcessor}s waiting on a barrier.\n\n *\n * <p>This strategy can be used when throughput and low-latency are not as important as CPU resource.\n */\npublic final class BlockingWaitStrategy implements WaitStrategy\n{\n    private final Object mutex = new Object();\n\n    @Override\n    public long waitFor(final long sequence, final Sequence cursorSequence, final Sequence dependentSequence, final SequenceBarrier barrier)\n        throws AlertException, InterruptedException\n    {\n        long availableSequence;\n        if (cursorSequence.get() < sequence)\n        {\n            synchronized (mutex)\n            {\n                while (cursorSequence.get() < sequence)\n                {\n                    barrier.checkAlert();\n                    mutex.wait();\n                }\n            }\n        }\n\n        while ((availableSequence = dependentSequence.get()) < sequence)\n        {\n            barrier.checkAlert();\n            Thread.onSpinWait();\n        }\n\n        return availableSequence;\n    }\n\n    @Override\n    public void signalAllWhenBlocking()\n    {\n        synchronized (mutex)\n        {\n            mutex.notifyAll();\n        }\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"BlockingWaitStrategy{\" +\n            \"mutex=\" + mutex +\n            '}';\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/BusySpinWaitStrategy.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Busy Spin strategy that uses a busy spin loop for {@link com.lmax.disruptor.EventProcessor}s waiting on a barrier.\n *\n * <p>This strategy will use CPU resource to avoid syscalls which can introduce latency jitter.  It is best\n * used when threads can be bound to specific CPU cores.\n */\npublic final class BusySpinWaitStrategy implements WaitStrategy\n{\n    @Override\n    public long waitFor(\n        final long sequence, final Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier)\n        throws AlertException, InterruptedException\n    {\n        long availableSequence;\n\n        while ((availableSequence = dependentSequence.get()) < sequence)\n        {\n            barrier.checkAlert();\n            Thread.onSpinWait();\n        }\n\n        return availableSequence;\n    }\n\n    @Override\n    public void signalAllWhenBlocking()\n    {\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/Cursored.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Implementors of this interface must provide a single long value\n * that represents their current cursor value.  Used during dynamic\n * add/remove of Sequences from a\n * {@link SequenceGroups#addSequences(Object, java.util.concurrent.atomic.AtomicReferenceFieldUpdater, Cursored, Sequence...)}.\n */\npublic interface Cursored\n{\n    /**\n     * Get the current cursor value.\n     *\n     * @return current cursor value\n     */\n    long getCursor();\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/DataProvider.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Typically used to decouple classes from {@link RingBuffer} to allow easier testing\n *\n * @param <T> The type provided by the implementation\n */\npublic interface DataProvider<T>\n{\n    /**\n     * @param sequence The sequence at which to find the data\n     * @return the data item located at that sequence\n     */\n    T get(long sequence);\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventFactory.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Called by the {@link RingBuffer} to pre-populate all the events to fill the RingBuffer.\n *\n * @param <T> event implementation storing the data for sharing during exchange or parallel coordination of an event.\n */\npublic interface EventFactory<T>\n{\n    /**\n     * Implementations should instantiate an event object, with all memory already allocated where possible.\n     *\n     * @return T newly constructed event instance.\n     */\n    T newInstance();\n}"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventHandler.java",
    "content": "/*\n * Copyright 2022 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Callback interface to be implemented for processing events as they become available in the {@link RingBuffer}\n *\n * @param <T> event implementation storing the data for sharing during exchange or parallel coordination of an event.\n * @see BatchEventProcessor#setExceptionHandler(ExceptionHandler) if you want to handle exceptions propagated out of the handler.\n */\npublic interface EventHandler<T> extends EventHandlerBase<T>\n{\n    /**\n     * Called when a publisher has published an event to the {@link RingBuffer}.  The {@link BatchEventProcessor} will\n     * read messages from the {@link RingBuffer} in batches, where a batch is all of the events available to be\n     * processed without having to wait for any new event to arrive.  This can be useful for event handlers that need\n     * to do slower operations like I/O as they can group together the data from multiple events into a single\n     * operation.  Implementations should ensure that the operation is always performed when endOfBatch is true as\n     * the time between that message and the next one is indeterminate.\n     *\n     * @param event      published to the {@link RingBuffer}\n     * @param sequence   of the event being processed\n     * @param endOfBatch flag to indicate if this is the last event in a batch from the {@link RingBuffer}\n     * @throws Exception if the EventHandler would like the exception handled further up the chain.\n     */\n    @Override\n    void onEvent(T event, long sequence, boolean endOfBatch) throws Exception;\n\n    /**\n     *  Used by the {@link BatchEventProcessor} to set a callback allowing the {@link EventHandler} to notify\n     *  when it has finished consuming an event if this happens after the {@link EventHandler#onEvent(Object, long, boolean)} call.\n     *\n     *  <p>Typically this would be used when the handler is performing some sort of batching operation such as writing to an IO\n     *  device; after the operation has completed, the implementation should call {@link Sequence#set} to update the\n     *  sequence and allow other processes that are dependent on this handler to progress.\n     *\n     * @param sequenceCallback callback on which to notify the {@link BatchEventProcessor} that the sequence has progressed.\n     */\n    default void setSequenceCallback(Sequence sequenceCallback)\n    {\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventHandlerBase.java",
    "content": "/*\n * Copyright 2022 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n@FunctionalInterface\ninterface EventHandlerBase<T> extends EventHandlerIdentity\n{\n    /**\n     * Called when a publisher has published an event to the {@link RingBuffer}.  The {@link BatchEventProcessor} will\n     * read messages from the {@link RingBuffer} in batches, where a batch is all of the events available to be\n     * processed without having to wait for any new event to arrive.  This can be useful for event handlers that need\n     * to do slower operations like I/O as they can group together the data from multiple events into a single\n     * operation.  Implementations should ensure that the operation is always performed when endOfBatch is true as\n     * the time between that message and the next one is indeterminate.\n     *\n     * @param event      published to the {@link RingBuffer}\n     * @param sequence   of the event being processed\n     * @param endOfBatch flag to indicate if this is the last event in a batch from the {@link RingBuffer}\n     * @throws Throwable if the EventHandler would like the exception handled further up the chain or possible rewind\n     * the batch if a {@link RewindableException} is thrown.\n     */\n    void onEvent(T event, long sequence, boolean endOfBatch) throws Throwable;\n\n    /**\n     * Invoked by {@link BatchEventProcessor} prior to processing a batch of events\n     *\n     * @param batchSize the size of the batch that is starting\n     * @param queueDepth the total number of queued up events including the batch about to be processed\n     */\n    default void onBatchStart(long batchSize, long queueDepth)\n    {\n    }\n\n    /**\n     * Called once on thread start before first event is available.\n     */\n    default void onStart()\n    {\n    }\n\n    /**\n     * Called once just before the event processing thread is shutdown.\n     *\n     * <p>Sequence event processing will already have stopped before this method is called. No events will\n     * be processed after this message.\n     */\n    default void onShutdown()\n    {\n    }\n\n    /**\n     * Invoked when a {@link BatchEventProcessor}'s {@link WaitStrategy} throws a {@link TimeoutException}.\n     *\n     * @param sequence - the last processed sequence.\n     * @throws Exception if the implementation is unable to handle this timeout.\n     */\n    default void onTimeout(long sequence) throws Exception\n    {\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventHandlerIdentity.java",
    "content": "package com.lmax.disruptor;\n\npublic interface EventHandlerIdentity\n{\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventPoller.java",
    "content": "package com.lmax.disruptor;\n\n/**\n * Experimental poll-based interface for the Disruptor. Unlike a {@link BatchEventProcessor},\n * an event poller allows the user to control the flow of execution. This makes it ideal\n * for interoperability with existing threads whose lifecycle is not controlled by the\n * disruptor DSL.\n *\n * @param <T> the type of event used.\n */\npublic class EventPoller<T>\n{\n    private final DataProvider<T> dataProvider;\n    private final Sequencer sequencer;\n    private final Sequence sequence;\n    private final Sequence gatingSequence;\n\n    /**\n     * A callback used to process events\n     *\n     * @param <T> the type of the event\n     */\n    public interface Handler<T>\n    {\n        /**\n         * Called for each event to consume it\n         *\n         * @param event the event\n         * @param sequence the sequence of the event\n         * @param endOfBatch whether this event is the last in the batch\n         * @return whether to continue consuming events. If {@code false}, the poller will not feed any more events\n         *         to the handler until {@link EventPoller#poll(Handler)} is called again\n         * @throws Exception any exceptions thrown by the handler will be propagated to the caller of {@code poll}\n         */\n        boolean onEvent(T event, long sequence, boolean endOfBatch) throws Exception;\n    }\n\n    /**\n     * Indicates the result of a call to {@link #poll(Handler)}\n     */\n    public enum PollState\n    {\n        /**\n         * The poller processed one or more events\n         */\n        PROCESSING,\n        /**\n         * The poller is waiting for gated sequences to advance before events become available\n         */\n        GATING,\n        /**\n         * No events need to be processed\n         */\n        IDLE\n    }\n\n    /**\n     * Creates an event poller. Most users will want {@link RingBuffer#newPoller(Sequence...)}\n     * which will set up the poller automatically\n     *\n     * @param dataProvider from which events are drawn\n     * @param sequencer the main sequencer which handles ordering of events\n     * @param sequence the sequence which will be used by this event poller\n     * @param gatingSequence the sequences to gate on\n     */\n    public EventPoller(\n        final DataProvider<T> dataProvider,\n        final Sequencer sequencer,\n        final Sequence sequence,\n        final Sequence gatingSequence)\n    {\n        this.dataProvider = dataProvider;\n        this.sequencer = sequencer;\n        this.sequence = sequence;\n        this.gatingSequence = gatingSequence;\n    }\n\n    /**\n     * Polls for events using the given handler. <br>\n     * <br>\n     * This poller will continue to feed events to the given handler until known available\n     * events are consumed or {@link Handler#onEvent(Object, long, boolean)} returns false. <br>\n     * <br>\n     * Note that it is possible for more events to become available while the current events\n     * are being processed. A further call to this method will process such events.\n     *\n     * @param eventHandler the handler used to consume events\n     * @return the state of the event poller after the poll is attempted\n     * @throws Exception exceptions thrown from the event handler are propagated to the caller\n     */\n    public PollState poll(final Handler<T> eventHandler) throws Exception\n    {\n        final long currentSequence = sequence.get();\n        long nextSequence = currentSequence + 1;\n        final long availableSequence = sequencer.getHighestPublishedSequence(nextSequence, gatingSequence.get());\n\n        if (nextSequence <= availableSequence)\n        {\n            boolean processNextEvent;\n            long processedSequence = currentSequence;\n\n            try\n            {\n                do\n                {\n                    final T event = dataProvider.get(nextSequence);\n                    processNextEvent = eventHandler.onEvent(event, nextSequence, nextSequence == availableSequence);\n                    processedSequence = nextSequence;\n                    nextSequence++;\n\n                }\n                while (nextSequence <= availableSequence && processNextEvent);\n            }\n            finally\n            {\n                sequence.set(processedSequence);\n            }\n\n            return PollState.PROCESSING;\n        }\n        else if (sequencer.getCursor() >= nextSequence)\n        {\n            return PollState.GATING;\n        }\n        else\n        {\n            return PollState.IDLE;\n        }\n    }\n\n    /**\n     * Creates an event poller. Most users will want {@link RingBuffer#newPoller(Sequence...)}\n     * which will set up the poller automatically\n     *\n     * @param dataProvider from which events are drawn\n     * @param sequencer the main sequencer which handles ordering of events\n     * @param sequence the sequence which will be used by this event poller\n     * @param cursorSequence the cursor sequence, usually of the ring buffer\n     * @param gatingSequences additional sequences to gate on\n     * @param <T> the type of the event\n     * @return the event poller\n     */\n    public static <T> EventPoller<T> newInstance(\n        final DataProvider<T> dataProvider,\n        final Sequencer sequencer,\n        final Sequence sequence,\n        final Sequence cursorSequence,\n        final Sequence... gatingSequences)\n    {\n        Sequence gatingSequence;\n        if (gatingSequences.length == 0)\n        {\n            gatingSequence = cursorSequence;\n        }\n        else if (gatingSequences.length == 1)\n        {\n            gatingSequence = gatingSequences[0];\n        }\n        else\n        {\n            gatingSequence = new FixedSequenceGroup(gatingSequences);\n        }\n\n        return new EventPoller<>(dataProvider, sequencer, sequence, gatingSequence);\n    }\n\n    /**\n     * Get the {@link Sequence} being used by this event poller\n     *\n     * @return the sequence used by the event poller\n     */\n    public Sequence getSequence()\n    {\n        return sequence;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventProcessor.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * An EventProcessor needs to be an implementation of a runnable that will poll for events from the {@link RingBuffer}\n * using the appropriate wait strategy.  It is unlikely that you will need to implement this interface yourself.\n * Look at using the {@link EventHandler} interface along with the pre-supplied BatchEventProcessor in the first\n * instance.\n *\n * <p>An EventProcessor will generally be associated with a Thread for execution.\n */\npublic interface EventProcessor extends Runnable\n{\n    /**\n     * Get a reference to the {@link Sequence} being used by this {@link EventProcessor}.\n     *\n     * @return reference to the {@link Sequence} for this {@link EventProcessor}\n     */\n    Sequence getSequence();\n\n    /**\n     * Signal that this EventProcessor should stop when it has finished consuming at the next clean break.\n     * It will call {@link SequenceBarrier#alert()} to notify the thread to check status.\n     */\n    void halt();\n\n    /**\n     * @return whether this event processor is running or not\n     * Implementations should ideally return false only when the associated thread is idle.\n     */\n    boolean isRunning();\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventSequencer.java",
    "content": "package com.lmax.disruptor;\n\n/**\n * Pulls together the low-level data access and sequencing operations of {@link RingBuffer}\n * @param <T> The event type\n */\npublic interface EventSequencer<T> extends DataProvider<T>, Sequenced\n{\n\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventSink.java",
    "content": "package com.lmax.disruptor;\n\n/**\n * Write interface for {@link RingBuffer}.\n * @param <E> The event type\n */\npublic interface EventSink<E>\n{\n    /**\n     * Publishes an event to the ring buffer.  It handles\n     * claiming the next sequence, getting the current (uninitialised)\n     * event from the ring buffer and publishing the claimed sequence\n     * after translation.\n     *\n     * @param translator The user specified translation for the event\n     */\n    void publishEvent(EventTranslator<E> translator);\n\n    /**\n     * Attempts to publish an event to the ring buffer.  It handles\n     * claiming the next sequence, getting the current (uninitialised)\n     * event from the ring buffer and publishing the claimed sequence\n     * after translation.  Will return false if specified capacity\n     * was not available.\n     *\n     * @param translator The user specified translation for the event\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     */\n    boolean tryPublishEvent(EventTranslator<E> translator);\n\n    /**\n     * Allows one user supplied argument.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param translator The user specified translation for the event\n     * @param arg0       A user supplied argument.\n     * @see #publishEvent(EventTranslator)\n     */\n    <A> void publishEvent(EventTranslatorOneArg<E, A> translator, A arg0);\n\n    /**\n     * Allows one user supplied argument.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param translator The user specified translation for the event\n     * @param arg0       A user supplied argument.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #tryPublishEvent(EventTranslator)\n     */\n    <A> boolean tryPublishEvent(EventTranslatorOneArg<E, A> translator, A arg0);\n\n    /**\n     * Allows two user supplied arguments.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param translator The user specified translation for the event\n     * @param arg0       A user supplied argument.\n     * @param arg1       A user supplied argument.\n     * @see #publishEvent(EventTranslator)\n     */\n    <A, B> void publishEvent(EventTranslatorTwoArg<E, A, B> translator, A arg0, B arg1);\n\n    /**\n     * Allows two user supplied arguments.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param translator The user specified translation for the event\n     * @param arg0       A user supplied argument.\n     * @param arg1       A user supplied argument.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #tryPublishEvent(EventTranslator)\n     */\n    <A, B> boolean tryPublishEvent(EventTranslatorTwoArg<E, A, B> translator, A arg0, B arg1);\n\n    /**\n     * Allows three user supplied arguments\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param <C> Class of the user supplied argument\n     * @param translator The user specified translation for the event\n     * @param arg0       A user supplied argument.\n     * @param arg1       A user supplied argument.\n     * @param arg2       A user supplied argument.\n     * @see #publishEvent(EventTranslator)\n     */\n    <A, B, C> void publishEvent(EventTranslatorThreeArg<E, A, B, C> translator, A arg0, B arg1, C arg2);\n\n    /**\n     * Allows three user supplied arguments\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param <C> Class of the user supplied argument\n     * @param translator The user specified translation for the event\n     * @param arg0       A user supplied argument.\n     * @param arg1       A user supplied argument.\n     * @param arg2       A user supplied argument.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #publishEvent(EventTranslator)\n     */\n    <A, B, C> boolean tryPublishEvent(EventTranslatorThreeArg<E, A, B, C> translator, A arg0, B arg1, C arg2);\n\n    /**\n     * Allows a variable number of user supplied arguments\n     *\n     * @param translator The user specified translation for the event\n     * @param args       User supplied arguments.\n     * @see #publishEvent(EventTranslator)\n     */\n    void publishEvent(EventTranslatorVararg<E> translator, Object... args);\n\n    /**\n     * Allows a variable number of user supplied arguments\n     *\n     * @param translator The user specified translation for the event\n     * @param args       User supplied arguments.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #publishEvent(EventTranslator)\n     */\n    boolean tryPublishEvent(EventTranslatorVararg<E> translator, Object... args);\n\n    /**\n     * <p>Publishes multiple events to the ring buffer.  It handles\n     * claiming the next sequence, getting the current (uninitialised)\n     * event from the ring buffer and publishing the claimed sequence\n     * after translation.</p>\n     *\n     * <p>With this call the data that is to be inserted into the ring\n     * buffer will be a field (either explicitly or captured anonymously),\n     * therefore this call will require an instance of the translator\n     * for each value that is to be inserted into the ring buffer.</p>\n     *\n     * @param translators The user specified translation for each event\n     */\n    void publishEvents(EventTranslator<E>[] translators);\n\n    /**\n     * <p>Publishes multiple events to the ring buffer.  It handles\n     * claiming the next sequence, getting the current (uninitialised)\n     * event from the ring buffer and publishing the claimed sequence\n     * after translation.</p>\n     *\n     * <p>With this call the data that is to be inserted into the ring\n     * buffer will be a field (either explicitly or captured anonymously),\n     * therefore this call will require an instance of the translator\n     * for each value that is to be inserted into the ring buffer.</p>\n     *\n     * @param translators   The user specified translation for each event\n     * @param batchStartsAt The first element of the array which is within the batch.\n     * @param batchSize     The actual size of the batch\n     */\n    void publishEvents(EventTranslator<E>[] translators, int batchStartsAt, int batchSize);\n\n    /**\n     * Attempts to publish multiple events to the ring buffer.  It handles\n     * claiming the next sequence, getting the current (uninitialised)\n     * event from the ring buffer and publishing the claimed sequence\n     * after translation.  Will return false if specified capacity\n     * was not available.\n     *\n     * @param translators The user specified translation for the event\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     */\n    boolean tryPublishEvents(EventTranslator<E>[] translators);\n\n    /**\n     * Attempts to publish multiple events to the ring buffer.  It handles\n     * claiming the next sequence, getting the current (uninitialised)\n     * event from the ring buffer and publishing the claimed sequence\n     * after translation.  Will return false if specified capacity\n     * was not available.\n     *\n     * @param translators   The user specified translation for the event\n     * @param batchStartsAt The first element of the array which is within the batch.\n     * @param batchSize     The actual size of the batch\n     * @return true if all the values were published, false if there was insufficient\n     * capacity.\n     */\n    boolean tryPublishEvents(EventTranslator<E>[] translators, int batchStartsAt, int batchSize);\n\n    /**\n     * Allows one user supplied argument per event.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param translator The user specified translation for the event\n     * @param arg0       A user supplied argument.\n     * @see #publishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    <A> void publishEvents(EventTranslatorOneArg<E, A> translator, A[] arg0);\n\n    /**\n     * Allows one user supplied argument per event.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param translator    The user specified translation for each event\n     * @param batchStartsAt The first element of the array which is within the batch.\n     * @param batchSize     The actual size of the batch\n     * @param arg0          An array of user supplied arguments, one element per event.\n     * @see #publishEvents(EventTranslator[])\n     */\n    <A> void publishEvents(EventTranslatorOneArg<E, A> translator, int batchStartsAt, int batchSize, A[] arg0);\n\n    /**\n     * Allows one user supplied argument.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param translator The user specified translation for each event\n     * @param arg0       An array of user supplied arguments, one element per event.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #tryPublishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    <A> boolean tryPublishEvents(EventTranslatorOneArg<E, A> translator, A[] arg0);\n\n    /**\n     * Allows one user supplied argument.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param translator    The user specified translation for each event\n     * @param batchStartsAt The first element of the array which is within the batch.\n     * @param batchSize     The actual size of the batch\n     * @param arg0          An array of user supplied arguments, one element per event.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #tryPublishEvents(EventTranslator[])\n     */\n    <A> boolean tryPublishEvents(EventTranslatorOneArg<E, A> translator, int batchStartsAt, int batchSize, A[] arg0);\n\n    /**\n     * Allows two user supplied arguments per event.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param translator The user specified translation for the event\n     * @param arg0       An array of user supplied arguments, one element per event.\n     * @param arg1       An array of user supplied arguments, one element per event.\n     * @see #publishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    <A, B> void publishEvents(EventTranslatorTwoArg<E, A, B> translator, A[] arg0, B[] arg1);\n\n    /**\n     * Allows two user supplied arguments per event.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param translator    The user specified translation for the event\n     * @param batchStartsAt The first element of the array which is within the batch.\n     * @param batchSize     The actual size of the batch.\n     * @param arg0          An array of user supplied arguments, one element per event.\n     * @param arg1          An array of user supplied arguments, one element per event.\n     * @see #publishEvents(EventTranslator[])\n     */\n    <A, B> void publishEvents(\n        EventTranslatorTwoArg<E, A, B> translator, int batchStartsAt, int batchSize, A[] arg0,\n        B[] arg1);\n\n    /**\n     * Allows two user supplied arguments per event.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param translator The user specified translation for the event\n     * @param arg0       An array of user supplied arguments, one element per event.\n     * @param arg1       An array of user supplied arguments, one element per event.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #tryPublishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    <A, B> boolean tryPublishEvents(EventTranslatorTwoArg<E, A, B> translator, A[] arg0, B[] arg1);\n\n    /**\n     * Allows two user supplied arguments per event.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param translator    The user specified translation for the event\n     * @param batchStartsAt The first element of the array which is within the batch.\n     * @param batchSize     The actual size of the batch.\n     * @param arg0          An array of user supplied arguments, one element per event.\n     * @param arg1          An array of user supplied arguments, one element per event.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #tryPublishEvents(EventTranslator[])\n     */\n    <A, B> boolean tryPublishEvents(\n        EventTranslatorTwoArg<E, A, B> translator, int batchStartsAt, int batchSize,\n        A[] arg0, B[] arg1);\n\n    /**\n     * Allows three user supplied arguments per event.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param <C> Class of the user supplied argument\n     * @param translator The user specified translation for the event\n     * @param arg0       An array of user supplied arguments, one element per event.\n     * @param arg1       An array of user supplied arguments, one element per event.\n     * @param arg2       An array of user supplied arguments, one element per event.\n     * @see #publishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    <A, B, C> void publishEvents(EventTranslatorThreeArg<E, A, B, C> translator, A[] arg0, B[] arg1, C[] arg2);\n\n    /**\n     * Allows three user supplied arguments per event.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param <C> Class of the user supplied argument\n     * @param translator    The user specified translation for the event\n     * @param batchStartsAt The first element of the array which is within the batch.\n     * @param batchSize     The number of elements in the batch.\n     * @param arg0          An array of user supplied arguments, one element per event.\n     * @param arg1          An array of user supplied arguments, one element per event.\n     * @param arg2          An array of user supplied arguments, one element per event.\n     * @see #publishEvents(EventTranslator[])\n     */\n    <A, B, C> void publishEvents(\n        EventTranslatorThreeArg<E, A, B, C> translator, int batchStartsAt, int batchSize,\n        A[] arg0, B[] arg1, C[] arg2);\n\n    /**\n     * Allows three user supplied arguments per event.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param <C> Class of the user supplied argument\n     * @param translator The user specified translation for the event\n     * @param arg0       An array of user supplied arguments, one element per event.\n     * @param arg1       An array of user supplied arguments, one element per event.\n     * @param arg2       An array of user supplied arguments, one element per event.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #publishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    <A, B, C> boolean tryPublishEvents(EventTranslatorThreeArg<E, A, B, C> translator, A[] arg0, B[] arg1, C[] arg2);\n\n    /**\n     * Allows three user supplied arguments per event.\n     *\n     * @param <A> Class of the user supplied argument\n     * @param <B> Class of the user supplied argument\n     * @param <C> Class of the user supplied argument\n     * @param translator    The user specified translation for the event\n     * @param batchStartsAt The first element of the array which is within the batch.\n     * @param batchSize     The actual size of the batch.\n     * @param arg0          An array of user supplied arguments, one element per event.\n     * @param arg1          An array of user supplied arguments, one element per event.\n     * @param arg2          An array of user supplied arguments, one element per event.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #publishEvents(EventTranslator[])\n     */\n    <A, B, C> boolean tryPublishEvents(\n        EventTranslatorThreeArg<E, A, B, C> translator, int batchStartsAt,\n        int batchSize, A[] arg0, B[] arg1, C[] arg2);\n\n    /**\n     * Allows a variable number of user supplied arguments per event.\n     *\n     * @param translator The user specified translation for the event\n     * @param args       User supplied arguments, one Object[] per event.\n     * @see #publishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    void publishEvents(EventTranslatorVararg<E> translator, Object[]... args);\n\n    /**\n     * Allows a variable number of user supplied arguments per event.\n     *\n     * @param translator    The user specified translation for the event\n     * @param batchStartsAt The first element of the array which is within the batch.\n     * @param batchSize     The actual size of the batch\n     * @param args          User supplied arguments, one Object[] per event.\n     * @see #publishEvents(EventTranslator[])\n     */\n    void publishEvents(EventTranslatorVararg<E> translator, int batchStartsAt, int batchSize, Object[]... args);\n\n    /**\n     * Allows a variable number of user supplied arguments per event.\n     *\n     * @param translator The user specified translation for the event\n     * @param args       User supplied arguments, one Object[] per event.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #publishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    boolean tryPublishEvents(EventTranslatorVararg<E> translator, Object[]... args);\n\n    /**\n     * Allows a variable number of user supplied arguments per event.\n     *\n     * @param translator    The user specified translation for the event\n     * @param batchStartsAt The first element of the array which is within the batch.\n     * @param batchSize     The actual size of the batch.\n     * @param args          User supplied arguments, one Object[] per event.\n     * @return true if the value was published, false if there was insufficient\n     * capacity.\n     * @see #publishEvents(EventTranslator[])\n     */\n    boolean tryPublishEvents(EventTranslatorVararg<E> translator, int batchStartsAt, int batchSize, Object[]... args);\n\n}"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventTranslator.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Implementations translate (write) data representations into events claimed from the {@link RingBuffer}.\n *\n * <p>When publishing to the RingBuffer, provide an EventTranslator. The RingBuffer will select the next available\n * event by sequence and provide it to the EventTranslator (which should update the event), before publishing\n * the sequence update.\n *\n * @param <T> event implementation storing the data for sharing during exchange or parallel coordination of an event.\n */\npublic interface EventTranslator<T>\n{\n    /**\n     * Translate a data representation into fields set in given event\n     *\n     * @param event    into which the data should be translated.\n     * @param sequence that is assigned to event.\n     */\n    void translateTo(T event, long sequence);\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventTranslatorOneArg.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Implementations translate another data representations into events claimed from the {@link RingBuffer}\n *\n * @param <T> event implementation storing the data for sharing during exchange or parallel coordination of an event.\n * @param <A> type first user specified argument to the translator.\n * @see EventTranslator\n */\npublic interface EventTranslatorOneArg<T, A>\n{\n    /**\n     * Translate a data representation into fields set in given event\n     *\n     * @param event    into which the data should be translated.\n     * @param sequence that is assigned to event.\n     * @param arg0     The first user specified argument to the translator\n     */\n    void translateTo(T event, long sequence, A arg0);\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventTranslatorThreeArg.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Implementations translate another data representations into events claimed from the {@link RingBuffer}\n *\n * @param <T> event implementation storing the data for sharing during exchange or parallel coordination of an event.\n * @param <A> type first user specified argument to the translator.\n * @param <B> type second user specified argument to the translator.\n * @param <C> type third user specified argument to the translator.\n * @see EventTranslator\n */\npublic interface EventTranslatorThreeArg<T, A, B, C>\n{\n    /**\n     * Translate a data representation into fields set in given event\n     *\n     * @param event    into which the data should be translated.\n     * @param sequence that is assigned to event.\n     * @param arg0     The first user specified argument to the translator\n     * @param arg1     The second user specified argument to the translator\n     * @param arg2     The third user specified argument to the translator\n     */\n    void translateTo(T event, long sequence, A arg0, B arg1, C arg2);\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventTranslatorTwoArg.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Implementations translate another data representations into events claimed from the {@link RingBuffer}\n *\n * @param <T> event implementation storing the data for sharing during exchange or parallel coordination of an event.\n * @param <A> type first user specified argument to the translator.\n * @param <B> type second user specified argument to the translator.\n * @see EventTranslator\n */\npublic interface EventTranslatorTwoArg<T, A, B>\n{\n    /**\n     * Translate a data representation into fields set in given event\n     *\n     * @param event    into which the data should be translated.\n     * @param sequence that is assigned to event.\n     * @param arg0     The first user specified argument to the translator\n     * @param arg1     The second user specified argument to the translator\n     */\n    void translateTo(T event, long sequence, A arg0, B arg1);\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventTranslatorVararg.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Implementations translate another data representations into events claimed from the {@link RingBuffer}\n *\n * @param <T> event implementation storing the data for sharing during exchange or parallel coordination of an event.\n * @see EventTranslator\n */\npublic interface EventTranslatorVararg<T>\n{\n    /**\n     * Translate a data representation into fields set in given event\n     *\n     * @param event    into which the data should be translated.\n     * @param sequence that is assigned to event.\n     * @param args     The array of user arguments.\n     */\n    void translateTo(T event, long sequence, Object... args);\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/EventuallyGiveUpBatchRewindStrategy.java",
    "content": "package com.lmax.disruptor;\n\n/**\n * <p>Strategy for handling a rewindableException that will eventually delegate the exception to the\n * {@link ExceptionHandler} after a specified number of attempts have been made.</p>\n */\npublic class EventuallyGiveUpBatchRewindStrategy implements BatchRewindStrategy\n{\n    private final long maxAttempts;\n\n    /**\n     * @param maxAttempts numbers of Rewindable exceptions that can be thrown until exception is delegated\n     */\n    public EventuallyGiveUpBatchRewindStrategy(final long maxAttempts)\n    {\n        this.maxAttempts = maxAttempts;\n    }\n\n    @Override\n    public RewindAction handleRewindException(final RewindableException e, final int retriesAttempted)\n    {\n        if (retriesAttempted == maxAttempts)\n        {\n            return RewindAction.THROW;\n        }\n        return RewindAction.REWIND;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/ExceptionHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Callback handler for uncaught exceptions in the event processing cycle of the {@link BatchEventProcessor}\n *\n * @param <T> implementation storing the data for sharing during exchange or parallel coordination of an event.\n */\npublic interface ExceptionHandler<T>\n{\n    /**\n     * <p>Strategy for handling uncaught exceptions when processing an event.</p>\n     *\n     * <p>If the strategy wishes to terminate further processing by the {@link BatchEventProcessor}\n     * then it should throw a {@link RuntimeException}.</p>\n     *\n     * @param ex       the exception that propagated from the {@link EventHandler}.\n     * @param sequence of the event which cause the exception.\n     * @param event    being processed when the exception occurred.  This can be null.\n     */\n    void handleEventException(Throwable ex, long sequence, T event);\n\n    /**\n     * Callback to notify of an exception during {@link EventHandler#onStart()}\n     *\n     * @param ex throw during the starting process.\n     */\n    void handleOnStartException(Throwable ex);\n\n    /**\n     * Callback to notify of an exception during {@link EventHandler#onShutdown()}\n     *\n     * @param ex throw during the shutdown process.\n     */\n    void handleOnShutdownException(Throwable ex);\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/ExceptionHandlers.java",
    "content": "/*\n * Copyright 2021 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/** Provides static methods for accessing a default {@link ExceptionHandler} object. */\npublic final class ExceptionHandlers\n{\n\n    /**\n     * Get a reference to the default {@link ExceptionHandler} instance.\n     *\n     * @return a reference to the default {@link ExceptionHandler} instance\n     */\n    public static ExceptionHandler<Object> defaultHandler()\n    {\n        return DefaultExceptionHandlerHolder.HANDLER;\n    }\n\n    private ExceptionHandlers()\n    {\n    }\n\n    // lazily initialize the default exception handler.\n    // This nested object isn't strictly necessary unless additional utility functionality is\n    // added to ExceptionHandlers, but it exists to ensure the code remains obvious.\n    private static final class DefaultExceptionHandlerHolder\n    {\n        private static final ExceptionHandler<Object> HANDLER = new FatalExceptionHandler();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/FatalExceptionHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport java.lang.System.Logger;\nimport java.lang.System.Logger.Level;\n\n/**\n * Convenience implementation of an exception handler that uses the standard JDK logging\n * of {@link System.Logger} to log the exception as {@link Level}.ERROR and re-throw\n * it wrapped in a {@link RuntimeException}\n */\npublic final class FatalExceptionHandler implements ExceptionHandler<Object>\n{\n    private static final Logger LOGGER = System.getLogger(FatalExceptionHandler.class.getName());\n\n    @Override\n    public void handleEventException(final Throwable ex, final long sequence, final Object event)\n    {\n        LOGGER.log(Level.ERROR, () -> \"Exception processing: \" + sequence + \" \" + event, ex);\n\n        throw new RuntimeException(ex);\n    }\n\n    @Override\n    public void handleOnStartException(final Throwable ex)\n    {\n        LOGGER.log(Level.ERROR, \"Exception during onStart()\", ex);\n    }\n\n    @Override\n    public void handleOnShutdownException(final Throwable ex)\n    {\n        LOGGER.log(Level.ERROR, \"Exception during onShutdown()\", ex);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/FixedSequenceGroup.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.util.Util;\n\nimport java.util.Arrays;\n\n/**\n * Hides a group of Sequences behind a single Sequence\n */\npublic final class FixedSequenceGroup extends Sequence\n{\n    private final Sequence[] sequences;\n\n    /**\n     * Constructor\n     *\n     * @param sequences the list of sequences to be tracked under this sequence group\n     */\n    public FixedSequenceGroup(final Sequence[] sequences)\n    {\n        this.sequences = Arrays.copyOf(sequences, sequences.length);\n    }\n\n    /**\n     * Get the minimum sequence value for the group.\n     *\n     * @return the minimum sequence value for the group.\n     */\n    @Override\n    public long get()\n    {\n        return Util.getMinimumSequence(sequences);\n    }\n\n    @Override\n    public String toString()\n    {\n        return Arrays.toString(sequences);\n    }\n\n    /**\n     * Not supported.\n     */\n    @Override\n    public void set(final long value)\n    {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Not supported.\n     */\n    @Override\n    public boolean compareAndSet(final long expectedValue, final long newValue)\n    {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Not supported.\n     */\n    @Override\n    public long incrementAndGet()\n    {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Not supported.\n     */\n    @Override\n    public long addAndGet(final long increment)\n    {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/IgnoreExceptionHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport java.lang.System.Logger;\nimport java.lang.System.Logger.Level;\n\n/**\n * Convenience implementation of an exception handler that uses the standard JDK logging\n * of {@link System.Logger} to log the exception as {@link Level}.INFO\n */\npublic final class IgnoreExceptionHandler implements ExceptionHandler<Object>\n{\n    private static final Logger LOGGER = System.getLogger(IgnoreExceptionHandler.class.getName());\n\n    @Override\n    public void handleEventException(final Throwable ex, final long sequence, final Object event)\n    {\n        LOGGER.log(Level.INFO, () -> \"Exception processing: \" + sequence + \" \" + event, ex);\n    }\n\n    @Override\n    public void handleOnStartException(final Throwable ex)\n    {\n        LOGGER.log(Level.INFO, \"Exception during onStart()\", ex);\n    }\n\n    @Override\n    public void handleOnShutdownException(final Throwable ex)\n    {\n        LOGGER.log(Level.INFO, \"Exception during onShutdown()\", ex);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/InsufficientCapacityException.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Exception thrown when it is not possible to insert a value into\n * the ring buffer without it wrapping the consuming sequences.  Used\n * specifically when claiming with the {@link RingBuffer#tryNext()} call.\n *\n * <p>For efficiency this exception will not have a stack trace.\n */\n@SuppressWarnings({\"serial\", \"lgtm[java/non-sync-override]\"})\npublic final class InsufficientCapacityException extends Exception\n{\n    /**\n     * The efficiency saving singleton instance\n     */\n    public static final InsufficientCapacityException INSTANCE = new InsufficientCapacityException();\n\n    private InsufficientCapacityException()\n    {\n        // Singleton\n    }\n\n    @Override\n    public Throwable fillInStackTrace()\n    {\n        return this;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/LiteBlockingWaitStrategy.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Variation of the {@link BlockingWaitStrategy} that attempts to elide conditional wake-ups when\n * the lock is uncontended.  Shows performance improvements on microbenchmarks.  However this\n * wait strategy should be considered experimental as I have not full proved the correctness of\n * the lock elision code.\n */\npublic final class LiteBlockingWaitStrategy implements WaitStrategy\n{\n    private final Object mutex = new Object();\n    private final AtomicBoolean signalNeeded = new AtomicBoolean(false);\n\n    @Override\n    public long waitFor(final long sequence, final Sequence cursorSequence, final Sequence dependentSequence, final SequenceBarrier barrier)\n        throws AlertException, InterruptedException\n    {\n        long availableSequence;\n        if (cursorSequence.get() < sequence)\n        {\n            synchronized (mutex)\n            {\n                do\n                {\n                    signalNeeded.getAndSet(true);\n\n                    if (cursorSequence.get() >= sequence)\n                    {\n                        break;\n                    }\n\n                    barrier.checkAlert();\n                    mutex.wait();\n                }\n                while (cursorSequence.get() < sequence);\n            }\n        }\n\n        while ((availableSequence = dependentSequence.get()) < sequence)\n        {\n            barrier.checkAlert();\n            Thread.onSpinWait();\n        }\n\n        return availableSequence;\n    }\n\n    @Override\n    public void signalAllWhenBlocking()\n    {\n        if (signalNeeded.getAndSet(false))\n        {\n            synchronized (mutex)\n            {\n                mutex.notifyAll();\n            }\n        }\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"LiteBlockingWaitStrategy{\" +\n            \"mutex=\" + mutex +\n            \", signalNeeded=\" + signalNeeded +\n            '}';\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/LiteTimeoutBlockingWaitStrategy.java",
    "content": "package com.lmax.disruptor;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static com.lmax.disruptor.util.Util.awaitNanos;\n\n/**\n * Variation of the {@link TimeoutBlockingWaitStrategy} that attempts to elide conditional wake-ups\n * when the lock is uncontended.\n */\npublic class LiteTimeoutBlockingWaitStrategy implements WaitStrategy\n{\n    private final Object mutex = new Object();\n    private final AtomicBoolean signalNeeded = new AtomicBoolean(false);\n    private final long timeoutInNanos;\n\n    /**\n     * @param timeout how long to wait before timing out\n     * @param units the unit in which timeout is specified\n     */\n    public LiteTimeoutBlockingWaitStrategy(final long timeout, final TimeUnit units)\n    {\n        timeoutInNanos = units.toNanos(timeout);\n    }\n\n    @Override\n    public long waitFor(\n        final long sequence,\n        final Sequence cursorSequence,\n        final Sequence dependentSequence,\n        final SequenceBarrier barrier)\n        throws AlertException, InterruptedException, TimeoutException\n    {\n        long nanos = timeoutInNanos;\n\n        long availableSequence;\n        if (cursorSequence.get() < sequence)\n        {\n            synchronized (mutex)\n            {\n                while (cursorSequence.get() < sequence)\n                {\n                    signalNeeded.getAndSet(true);\n\n                    barrier.checkAlert();\n                    nanos = awaitNanos(mutex, nanos);\n                    if (nanos <= 0)\n                    {\n                        throw TimeoutException.INSTANCE;\n                    }\n                }\n            }\n        }\n\n        while ((availableSequence = dependentSequence.get()) < sequence)\n        {\n            barrier.checkAlert();\n        }\n\n        return availableSequence;\n    }\n\n    @Override\n    public void signalAllWhenBlocking()\n    {\n        if (signalNeeded.getAndSet(false))\n        {\n            synchronized (mutex)\n            {\n                mutex.notifyAll();\n            }\n        }\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"LiteTimeoutBlockingWaitStrategy{\" +\n            \"mutex=\" + mutex +\n            \", signalNeeded=\" + signalNeeded +\n            \", timeoutInNanos=\" + timeoutInNanos +\n            '}';\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/MultiProducerSequencer.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.util.Util;\n\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.VarHandle;\nimport java.util.Arrays;\nimport java.util.concurrent.locks.LockSupport;\n\n\n/**\n * Coordinator for claiming sequences for access to a data structure while tracking dependent {@link Sequence}s.\n * Suitable for use for sequencing across multiple publisher threads.\n *\n * <p>Note on {@link Sequencer#getCursor()}:  With this sequencer the cursor value is updated after the call\n * to {@link Sequencer#next()}, to determine the highest available sequence that can be read, then\n * {@link Sequencer#getHighestPublishedSequence(long, long)} should be used.\n */\npublic final class MultiProducerSequencer extends AbstractSequencer\n{\n    private static final VarHandle AVAILABLE_ARRAY = MethodHandles.arrayElementVarHandle(int[].class);\n\n    private final Sequence gatingSequenceCache = new Sequence(Sequencer.INITIAL_CURSOR_VALUE);\n\n    // availableBuffer tracks the state of each ringbuffer slot\n    // see below for more details on the approach\n    private final int[] availableBuffer;\n    private final int indexMask;\n    private final int indexShift;\n\n    /**\n     * Construct a Sequencer with the selected wait strategy and buffer size.\n     *\n     * @param bufferSize   the size of the buffer that this will sequence over.\n     * @param waitStrategy for those waiting on sequences.\n     */\n    public MultiProducerSequencer(final int bufferSize, final WaitStrategy waitStrategy)\n    {\n        super(bufferSize, waitStrategy);\n        availableBuffer = new int[bufferSize];\n        Arrays.fill(availableBuffer, -1);\n\n        indexMask = bufferSize - 1;\n        indexShift = Util.log2(bufferSize);\n    }\n\n    /**\n     * @see Sequencer#hasAvailableCapacity(int)\n     */\n    @Override\n    public boolean hasAvailableCapacity(final int requiredCapacity)\n    {\n        return hasAvailableCapacity(gatingSequences, requiredCapacity, cursor.get());\n    }\n\n    private boolean hasAvailableCapacity(final Sequence[] gatingSequences, final int requiredCapacity, final long cursorValue)\n    {\n        long wrapPoint = (cursorValue + requiredCapacity) - bufferSize;\n        long cachedGatingSequence = gatingSequenceCache.get();\n\n        if (wrapPoint > cachedGatingSequence || cachedGatingSequence > cursorValue)\n        {\n            long minSequence = Util.getMinimumSequence(gatingSequences, cursorValue);\n            gatingSequenceCache.set(minSequence);\n\n            if (wrapPoint > minSequence)\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * @see Sequencer#claim(long)\n     */\n    @Override\n    public void claim(final long sequence)\n    {\n        cursor.set(sequence);\n    }\n\n    /**\n     * @see Sequencer#next()\n     */\n    @Override\n    public long next()\n    {\n        return next(1);\n    }\n\n    /**\n     * @see Sequencer#next(int)\n     */\n    @Override\n    public long next(final int n)\n    {\n        if (n < 1 || n > bufferSize)\n        {\n            throw new IllegalArgumentException(\"n must be > 0 and < bufferSize\");\n        }\n\n        long current = cursor.getAndAdd(n);\n\n        long nextSequence = current + n;\n        long wrapPoint = nextSequence - bufferSize;\n        long cachedGatingSequence = gatingSequenceCache.get();\n\n        if (wrapPoint > cachedGatingSequence || cachedGatingSequence > current)\n        {\n            long gatingSequence;\n            while (wrapPoint > (gatingSequence = Util.getMinimumSequence(gatingSequences, current)))\n            {\n                LockSupport.parkNanos(1L); // TODO, should we spin based on the wait strategy?\n            }\n\n            gatingSequenceCache.set(gatingSequence);\n        }\n\n        return nextSequence;\n    }\n\n    /**\n     * @see Sequencer#tryNext()\n     */\n    @Override\n    public long tryNext() throws InsufficientCapacityException\n    {\n        return tryNext(1);\n    }\n\n    /**\n     * @see Sequencer#tryNext(int)\n     */\n    @Override\n    public long tryNext(final int n) throws InsufficientCapacityException\n    {\n        if (n < 1)\n        {\n            throw new IllegalArgumentException(\"n must be > 0\");\n        }\n\n        long current;\n        long next;\n\n        do\n        {\n            current = cursor.get();\n            next = current + n;\n\n            if (!hasAvailableCapacity(gatingSequences, n, current))\n            {\n                throw InsufficientCapacityException.INSTANCE;\n            }\n        }\n        while (!cursor.compareAndSet(current, next));\n\n        return next;\n    }\n\n    /**\n     * @see Sequencer#remainingCapacity()\n     */\n    @Override\n    public long remainingCapacity()\n    {\n        long consumed = Util.getMinimumSequence(gatingSequences, cursor.get());\n        long produced = cursor.get();\n        return getBufferSize() - (produced - consumed);\n    }\n\n    /**\n     * @see Sequencer#publish(long)\n     */\n    @Override\n    public void publish(final long sequence)\n    {\n        setAvailable(sequence);\n        waitStrategy.signalAllWhenBlocking();\n    }\n\n    /**\n     * @see Sequencer#publish(long, long)\n     */\n    @Override\n    public void publish(final long lo, final long hi)\n    {\n        for (long l = lo; l <= hi; l++)\n        {\n            setAvailable(l);\n        }\n        waitStrategy.signalAllWhenBlocking();\n    }\n\n    /**\n     * The below methods work on the availableBuffer flag.\n     *\n     * <p>The prime reason is to avoid a shared sequence object between publisher threads.\n     * (Keeping single pointers tracking start and end would require coordination\n     * between the threads).\n     *\n     * <p>--  Firstly we have the constraint that the delta between the cursor and minimum\n     * gating sequence will never be larger than the buffer size (the code in\n     * next/tryNext in the Sequence takes care of that).\n     * -- Given that; take the sequence value and mask off the lower portion of the\n     * sequence as the index into the buffer (indexMask). (aka modulo operator)\n     * -- The upper portion of the sequence becomes the value to check for availability.\n     * ie: it tells us how many times around the ring buffer we've been (aka division)\n     * -- Because we can't wrap without the gating sequences moving forward (i.e. the\n     * minimum gating sequence is effectively our last available position in the\n     * buffer), when we have new data and successfully claimed a slot we can simply\n     * write over the top.\n     */\n    private void setAvailable(final long sequence)\n    {\n        setAvailableBufferValue(calculateIndex(sequence), calculateAvailabilityFlag(sequence));\n    }\n\n    private void setAvailableBufferValue(final int index, final int flag)\n    {\n        AVAILABLE_ARRAY.setRelease(availableBuffer, index, flag);\n    }\n\n    /**\n     * @see Sequencer#isAvailable(long)\n     */\n    @Override\n    public boolean isAvailable(final long sequence)\n    {\n        int index = calculateIndex(sequence);\n        int flag = calculateAvailabilityFlag(sequence);\n        return (int) AVAILABLE_ARRAY.getAcquire(availableBuffer, index) == flag;\n    }\n\n    @Override\n    public long getHighestPublishedSequence(final long lowerBound, final long availableSequence)\n    {\n        for (long sequence = lowerBound; sequence <= availableSequence; sequence++)\n        {\n            if (!isAvailable(sequence))\n            {\n                return sequence - 1;\n            }\n        }\n\n        return availableSequence;\n    }\n\n    private int calculateAvailabilityFlag(final long sequence)\n    {\n        return (int) (sequence >>> indexShift);\n    }\n\n    private int calculateIndex(final long sequence)\n    {\n        return ((int) sequence) & indexMask;\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"MultiProducerSequencer{\" +\n                \"bufferSize=\" + bufferSize +\n                \", waitStrategy=\" + waitStrategy +\n                \", cursor=\" + cursor +\n                \", gatingSequences=\" + Arrays.toString(gatingSequences) +\n                '}';\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/NanosecondPauseBatchRewindStrategy.java",
    "content": "package com.lmax.disruptor;\n\nimport java.util.concurrent.locks.LockSupport;\n\n/**\n * <p>Strategy for handling a rewindableException that will pause for a specified amount of nanos.</p>\n */\npublic class NanosecondPauseBatchRewindStrategy implements BatchRewindStrategy\n{\n\n    private final long nanoSecondPauseTime;\n\n    /**\n     * <p>Strategy for handling a rewindableException that will pause for a specified amount of nanos.</p>\n     * @param  nanoSecondPauseTime Amount of nanos to pause for when a rewindable exception is thrown\n     */\n    public NanosecondPauseBatchRewindStrategy(final long nanoSecondPauseTime)\n    {\n        this.nanoSecondPauseTime = nanoSecondPauseTime;\n    }\n\n    @Override\n    public RewindAction handleRewindException(final RewindableException e, final int retriesAttempted)\n    {\n        LockSupport.parkNanos(nanoSecondPauseTime);\n        return RewindAction.REWIND;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/NoOpEventProcessor.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * No operation version of a {@link EventProcessor} that simply tracks a {@link Sequence}.\n *\n * <p>This is useful in tests or for pre-filling a {@link RingBuffer} from a publisher.\n */\npublic final class NoOpEventProcessor implements EventProcessor\n{\n    private final SequencerFollowingSequence sequence;\n    private final AtomicBoolean running = new AtomicBoolean(false);\n\n    /**\n     * Construct a {@link EventProcessor} that simply tracks a {@link Sequence} object.\n     *\n     * @param sequencer to track.\n     */\n    public NoOpEventProcessor(final RingBuffer<?> sequencer)\n    {\n        sequence = new SequencerFollowingSequence(sequencer);\n    }\n\n    @Override\n    public Sequence getSequence()\n    {\n        return sequence;\n    }\n\n    @Override\n    public void halt()\n    {\n        running.set(false);\n    }\n\n    @Override\n    public boolean isRunning()\n    {\n        return running.get();\n    }\n\n    @Override\n    public void run()\n    {\n        if (!running.compareAndSet(false, true))\n        {\n            throw new IllegalStateException(\"Thread is already running\");\n        }\n    }\n\n    /**\n     * Sequence that follows (by wrapping) another sequence\n     */\n    private static final class SequencerFollowingSequence extends Sequence\n    {\n        private final RingBuffer<?> sequencer;\n\n        private SequencerFollowingSequence(final RingBuffer<?> sequencer)\n        {\n            super(Sequencer.INITIAL_CURSOR_VALUE);\n            this.sequencer = sequencer;\n        }\n\n        @Override\n        public long get()\n        {\n            return sequencer.getCursor();\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/PhasedBackoffWaitStrategy.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Phased wait strategy for waiting {@link EventProcessor}s on a barrier.\n *\n * <p>This strategy can be used when throughput and low-latency are not as important as CPU resource.\n * Spins, then yields, then waits using the configured fallback WaitStrategy.\n */\npublic final class PhasedBackoffWaitStrategy implements WaitStrategy\n{\n    private static final int SPIN_TRIES = 10000;\n    private final long spinTimeoutNanos;\n    private final long yieldTimeoutNanos;\n    private final WaitStrategy fallbackStrategy;\n\n    /**\n     *\n     * @param spinTimeout The maximum time in to busy spin for.\n     * @param yieldTimeout The maximum time in to yield for.\n     * @param units Time units used for the timeout values.\n     * @param fallbackStrategy After spinning + yielding, the strategy to fall back to\n     */\n    public PhasedBackoffWaitStrategy(\n        final long spinTimeout,\n        final long yieldTimeout,\n        final TimeUnit units,\n        final WaitStrategy fallbackStrategy)\n    {\n        this.spinTimeoutNanos = units.toNanos(spinTimeout);\n        this.yieldTimeoutNanos = spinTimeoutNanos + units.toNanos(yieldTimeout);\n        this.fallbackStrategy = fallbackStrategy;\n    }\n\n    /**\n     * Construct {@link PhasedBackoffWaitStrategy} with fallback to {@link BlockingWaitStrategy}\n     *\n     * @param spinTimeout The maximum time in to busy spin for.\n     * @param yieldTimeout The maximum time in to yield for.\n     * @param units Time units used for the timeout values.\n     * @return The constructed wait strategy.\n     */\n    public static PhasedBackoffWaitStrategy withLock(\n        final long spinTimeout,\n        final long yieldTimeout,\n        final TimeUnit units)\n    {\n        return new PhasedBackoffWaitStrategy(\n            spinTimeout, yieldTimeout,\n            units, new BlockingWaitStrategy());\n    }\n\n    /**\n     * Construct {@link PhasedBackoffWaitStrategy} with fallback to {@link LiteBlockingWaitStrategy}\n     *\n     * @param spinTimeout The maximum time in to busy spin for.\n     * @param yieldTimeout The maximum time in to yield for.\n     * @param units Time units used for the timeout values.\n     * @return The constructed wait strategy.\n     */\n    public static PhasedBackoffWaitStrategy withLiteLock(\n        final long spinTimeout,\n        final long yieldTimeout,\n        final TimeUnit units)\n    {\n        return new PhasedBackoffWaitStrategy(\n            spinTimeout, yieldTimeout,\n            units, new LiteBlockingWaitStrategy());\n    }\n\n    /**\n     * Construct {@link PhasedBackoffWaitStrategy} with fallback to {@link SleepingWaitStrategy}\n     *\n     * @param spinTimeout The maximum time in to busy spin for.\n     * @param yieldTimeout The maximum time in to yield for.\n     * @param units Time units used for the timeout values.\n     * @return The constructed wait strategy.\n     */\n    public static PhasedBackoffWaitStrategy withSleep(\n        final long spinTimeout,\n        final long yieldTimeout,\n        final TimeUnit units)\n    {\n        return new PhasedBackoffWaitStrategy(\n            spinTimeout, yieldTimeout,\n            units, new SleepingWaitStrategy(0));\n    }\n\n    @Override\n    public long waitFor(final long sequence, final Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier)\n        throws AlertException, InterruptedException, TimeoutException\n    {\n        long availableSequence;\n        long startTime = 0;\n        int counter = SPIN_TRIES;\n\n        do\n        {\n            if ((availableSequence = dependentSequence.get()) >= sequence)\n            {\n                return availableSequence;\n            }\n\n            if (0 == --counter)\n            {\n                if (0 == startTime)\n                {\n                    startTime = System.nanoTime();\n                }\n                else\n                {\n                    long timeDelta = System.nanoTime() - startTime;\n                    if (timeDelta > yieldTimeoutNanos)\n                    {\n                        return fallbackStrategy.waitFor(sequence, cursor, dependentSequence, barrier);\n                    }\n                    else if (timeDelta > spinTimeoutNanos)\n                    {\n                        Thread.yield();\n                    }\n                }\n                counter = SPIN_TRIES;\n            }\n        }\n        while (true);\n    }\n\n    @Override\n    public void signalAllWhenBlocking()\n    {\n        fallbackStrategy.signalAllWhenBlocking();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/ProcessingSequenceBarrier.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n\n/**\n * {@link SequenceBarrier} handed out for gating {@link EventProcessor}s on a cursor sequence and optional dependent {@link EventProcessor}(s),\n * using the given WaitStrategy.\n */\nfinal class ProcessingSequenceBarrier implements SequenceBarrier\n{\n    private final WaitStrategy waitStrategy;\n    private final Sequence dependentSequence;\n    private volatile boolean alerted = false;\n    private final Sequence cursorSequence;\n    private final Sequencer sequencer;\n\n    ProcessingSequenceBarrier(\n        final Sequencer sequencer,\n        final WaitStrategy waitStrategy,\n        final Sequence cursorSequence,\n        final Sequence[] dependentSequences)\n    {\n        this.sequencer = sequencer;\n        this.waitStrategy = waitStrategy;\n        this.cursorSequence = cursorSequence;\n        if (0 == dependentSequences.length)\n        {\n            dependentSequence = cursorSequence;\n        }\n        else\n        {\n            dependentSequence = new FixedSequenceGroup(dependentSequences);\n        }\n    }\n\n    @Override\n    public long waitFor(final long sequence)\n        throws AlertException, InterruptedException, TimeoutException\n    {\n        checkAlert();\n\n        long availableSequence = waitStrategy.waitFor(sequence, cursorSequence, dependentSequence, this);\n\n        if (availableSequence < sequence)\n        {\n            return availableSequence;\n        }\n\n        return sequencer.getHighestPublishedSequence(sequence, availableSequence);\n    }\n\n    @Override\n    public long getCursor()\n    {\n        return dependentSequence.get();\n    }\n\n    @Override\n    public boolean isAlerted()\n    {\n        return alerted;\n    }\n\n    @Override\n    public void alert()\n    {\n        alerted = true;\n        waitStrategy.signalAllWhenBlocking();\n    }\n\n    @Override\n    public void clearAlert()\n    {\n        alerted = false;\n    }\n\n    @Override\n    public void checkAlert() throws AlertException\n    {\n        if (alerted)\n        {\n            throw AlertException.INSTANCE;\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/RewindAction.java",
    "content": "package com.lmax.disruptor;\n\n/**\n * The result returned from the {@link BatchRewindStrategy} that decides whether to rewind or throw the exception\n */\npublic enum RewindAction\n{\n    /**\n     * Rewind and replay the whole batch from  he beginning\n     */\n    REWIND,\n\n    /**\n     * rethrows the exception, delegating it to the configured {@link ExceptionHandler}\n     */\n    THROW\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/RewindHandler.java",
    "content": "/*\n * Copyright 2023 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lmax.disruptor;\n\npublic interface RewindHandler\n{\n    long attemptRewindGetNextSequence(RewindableException e, long startOfBatchSequence) throws RewindableException;\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/RewindableEventHandler.java",
    "content": "/*\n * Copyright 2022 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Callback interface to be implemented for processing events as they become available in the {@link RingBuffer}\n * with support for throwing a {@link RewindableException} when an even cannot be processed currently but may succeed on retry.\n *\n * @param <T> event implementation storing the data for sharing during exchange or parallel coordination of an event.\n * @see BatchEventProcessor#setExceptionHandler(ExceptionHandler) if you want to handle exceptions propagated out of the handler.\n */\npublic interface RewindableEventHandler<T> extends EventHandlerBase<T>\n{\n    /**\n     * Called when a publisher has published an event to the {@link RingBuffer}.  The {@link BatchEventProcessor} will\n     * read messages from the {@link RingBuffer} in batches, where a batch is all of the events available to be\n     * processed without having to wait for any new event to arrive.  This can be useful for event handlers that need\n     * to do slower operations like I/O as they can group together the data from multiple events into a single\n     * operation.  Implementations should ensure that the operation is always performed when endOfBatch is true as\n     * the time between that message and the next one is indeterminate.\n     *\n     * @param event      published to the {@link RingBuffer}\n     * @param sequence   of the event being processed\n     * @param endOfBatch flag to indicate if this is the last event in a batch from the {@link RingBuffer}\n     * @throws RewindableException if the EventHandler would like the batch event processor to process the entire batch again.\n     * @throws Exception if the EventHandler would like the exception handled further up the chain.\n     */\n    @Override\n    void onEvent(T event, long sequence, boolean endOfBatch) throws RewindableException, Exception;\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/RewindableException.java",
    "content": "package com.lmax.disruptor;\n\n/**\n * A special exception that can be thrown while using the {@link BatchEventProcessor}.\n * On throwing this exception the {@link BatchEventProcessor} can choose to rewind and replay the batch or throw\n * depending on the {@link BatchRewindStrategy}\n */\npublic class RewindableException extends Throwable\n{\n    /**\n     * @param cause The underlying cause of the exception.\n     */\n    public RewindableException(final Throwable cause)\n    {\n        super(\"REWINDING BATCH\", cause);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/RingBuffer.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n\nimport com.lmax.disruptor.dsl.ProducerType;\n\nabstract class RingBufferPad\n{\n    protected byte\n        p10, p11, p12, p13, p14, p15, p16, p17,\n        p20, p21, p22, p23, p24, p25, p26, p27,\n        p30, p31, p32, p33, p34, p35, p36, p37,\n        p40, p41, p42, p43, p44, p45, p46, p47,\n        p50, p51, p52, p53, p54, p55, p56, p57,\n        p60, p61, p62, p63, p64, p65, p66, p67,\n        p70, p71, p72, p73, p74, p75, p76, p77;\n}\n\nabstract class RingBufferFields<E> extends RingBufferPad\n{\n    private static final int BUFFER_PAD = 32;\n\n    private final long indexMask;\n    private final E[] entries;\n    protected final int bufferSize;\n    protected final Sequencer sequencer;\n\n    @SuppressWarnings(\"unchecked\")\n    RingBufferFields(\n        final EventFactory<E> eventFactory,\n        final Sequencer sequencer)\n    {\n        this.sequencer = sequencer;\n        this.bufferSize = sequencer.getBufferSize();\n\n        if (bufferSize < 1)\n        {\n            throw new IllegalArgumentException(\"bufferSize must not be less than 1\");\n        }\n        if (Integer.bitCount(bufferSize) != 1)\n        {\n            throw new IllegalArgumentException(\"bufferSize must be a power of 2\");\n        }\n\n        this.indexMask = bufferSize - 1;\n        this.entries = (E[]) new Object[bufferSize + 2 * BUFFER_PAD];\n        fill(eventFactory);\n    }\n\n    private void fill(final EventFactory<E> eventFactory)\n    {\n        for (int i = 0; i < bufferSize; i++)\n        {\n            entries[BUFFER_PAD + i] = eventFactory.newInstance();\n        }\n    }\n\n    protected final E elementAt(final long sequence)\n    {\n        return entries[BUFFER_PAD + (int) (sequence & indexMask)];\n    }\n}\n\n/**\n * Ring based store of reusable entries containing the data representing\n * an event being exchanged between event producer and {@link EventProcessor}s.\n *\n * @param <E> implementation storing the data for sharing during exchange or parallel coordination of an event.\n */\npublic final class RingBuffer<E> extends RingBufferFields<E> implements Cursored, EventSequencer<E>, EventSink<E>\n{\n    /**\n     * The initial cursor value\n     */\n    public static final long INITIAL_CURSOR_VALUE = Sequence.INITIAL_VALUE;\n    protected byte\n        p10, p11, p12, p13, p14, p15, p16, p17,\n        p20, p21, p22, p23, p24, p25, p26, p27,\n        p30, p31, p32, p33, p34, p35, p36, p37,\n        p40, p41, p42, p43, p44, p45, p46, p47,\n        p50, p51, p52, p53, p54, p55, p56, p57,\n        p60, p61, p62, p63, p64, p65, p66, p67,\n        p70, p71, p72, p73, p74, p75, p76, p77;\n\n    /**\n     * Construct a RingBuffer with the full option set.\n     *\n     * @param eventFactory to newInstance entries for filling the RingBuffer\n     * @param sequencer    sequencer to handle the ordering of events moving through the RingBuffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     */\n    RingBuffer(\n        final EventFactory<E> eventFactory,\n        final Sequencer sequencer)\n    {\n        super(eventFactory, sequencer);\n    }\n\n    /**\n     * Create a new multiple producer RingBuffer with the specified wait strategy.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory      used to create the events within the ring buffer.\n     * @param bufferSize   number of elements to create within the ring buffer.\n     * @param waitStrategy used to determine how to wait for new elements to become available.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     * @see MultiProducerSequencer\n     */\n    public static <E> RingBuffer<E> createMultiProducer(\n        final EventFactory<E> factory,\n        final int bufferSize,\n        final WaitStrategy waitStrategy)\n    {\n        MultiProducerSequencer sequencer = new MultiProducerSequencer(bufferSize, waitStrategy);\n\n        return new RingBuffer<>(factory, sequencer);\n    }\n\n    /**\n     * Create a new multiple producer RingBuffer using the default wait strategy  {@link BlockingWaitStrategy}.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory    used to create the events within the ring buffer.\n     * @param bufferSize number of elements to create within the ring buffer.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if <code>bufferSize</code> is less than 1 or not a power of 2\n     * @see MultiProducerSequencer\n     */\n    public static <E> RingBuffer<E> createMultiProducer(final EventFactory<E> factory, final int bufferSize)\n    {\n        return createMultiProducer(factory, bufferSize, new BlockingWaitStrategy());\n    }\n\n    /**\n     * Create a new single producer RingBuffer with the specified wait strategy.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory      used to create the events within the ring buffer.\n     * @param bufferSize   number of elements to create within the ring buffer.\n     * @param waitStrategy used to determine how to wait for new elements to become available.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     * @see SingleProducerSequencer\n     */\n    public static <E> RingBuffer<E> createSingleProducer(\n        final EventFactory<E> factory,\n        final int bufferSize,\n        final WaitStrategy waitStrategy)\n    {\n        SingleProducerSequencer sequencer = new SingleProducerSequencer(bufferSize, waitStrategy);\n\n        return new RingBuffer<>(factory, sequencer);\n    }\n\n    /**\n     * Create a new single producer RingBuffer using the default wait strategy  {@link BlockingWaitStrategy}.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory    used to create the events within the ring buffer.\n     * @param bufferSize number of elements to create within the ring buffer.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if <code>bufferSize</code> is less than 1 or not a power of 2\n     * @see MultiProducerSequencer\n     */\n    public static <E> RingBuffer<E> createSingleProducer(final EventFactory<E> factory, final int bufferSize)\n    {\n        return createSingleProducer(factory, bufferSize, new BlockingWaitStrategy());\n    }\n\n    /**\n     * Create a new Ring Buffer with the specified producer type (SINGLE or MULTI)\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param producerType producer type to use {@link ProducerType}.\n     * @param factory      used to create events within the ring buffer.\n     * @param bufferSize   number of elements to create within the ring buffer.\n     * @param waitStrategy used to determine how to wait for new elements to become available.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     */\n    public static <E> RingBuffer<E> create(\n        final ProducerType producerType,\n        final EventFactory<E> factory,\n        final int bufferSize,\n        final WaitStrategy waitStrategy)\n    {\n        switch (producerType)\n        {\n            case SINGLE:\n                return createSingleProducer(factory, bufferSize, waitStrategy);\n            case MULTI:\n                return createMultiProducer(factory, bufferSize, waitStrategy);\n            default:\n                throw new IllegalStateException(producerType.toString());\n        }\n    }\n\n    /**\n     * <p>Get the event for a given sequence in the RingBuffer.</p>\n     *\n     * <p>This call has 2 uses.  Firstly use this call when publishing to a ring buffer.\n     * After calling {@link RingBuffer#next()} use this call to get hold of the\n     * preallocated event to fill with data before calling {@link RingBuffer#publish(long)}.</p>\n     *\n     * <p>Secondly use this call when consuming data from the ring buffer.  After calling\n     * {@link SequenceBarrier#waitFor(long)} call this method with any value greater than\n     * that your current consumer sequence and less than or equal to the value returned from\n     * the {@link SequenceBarrier#waitFor(long)} method.</p>\n     *\n     * @param sequence for the event\n     * @return the event for the given sequence\n     */\n    @Override\n    public E get(final long sequence)\n    {\n        return elementAt(sequence);\n    }\n\n    /**\n     * Increment and return the next sequence for the ring buffer.  Calls of this\n     * method should ensure that they always publish the sequence afterward.  E.g.\n     * <pre>\n     * long sequence = ringBuffer.next();\n     * try {\n     *     Event e = ringBuffer.get(sequence);\n     *     // Do some work with the event.\n     * } finally {\n     *     ringBuffer.publish(sequence);\n     * }\n     * </pre>\n     *\n     * @return The next sequence to publish to.\n     * @see RingBuffer#publish(long)\n     * @see RingBuffer#get(long)\n     */\n    @Override\n    public long next()\n    {\n        return sequencer.next();\n    }\n\n    /**\n     * The same functionality as {@link RingBuffer#next()}, but allows the caller to claim\n     * the next n sequences.\n     *\n     * @param n number of slots to claim\n     * @return sequence number of the highest slot claimed\n     * @see Sequencer#next(int)\n     */\n    @Override\n    public long next(final int n)\n    {\n        return sequencer.next(n);\n    }\n\n    /**\n     * <p>Increment and return the next sequence for the ring buffer.  Calls of this\n     * method should ensure that they always publish the sequence afterward.  E.g.</p>\n     * <pre>\n     * long sequence = ringBuffer.next();\n     * try {\n     *     Event e = ringBuffer.get(sequence);\n     *     // Do some work with the event.\n     * } finally {\n     *     ringBuffer.publish(sequence);\n     * }\n     * </pre>\n     * <p>This method will not block if there is not space available in the ring\n     * buffer, instead it will throw an {@link InsufficientCapacityException}.</p>\n     *\n     * @return The next sequence to publish to.\n     * @throws InsufficientCapacityException if the necessary space in the ring buffer is not available\n     * @see RingBuffer#publish(long)\n     * @see RingBuffer#get(long)\n     */\n    @Override\n    public long tryNext() throws InsufficientCapacityException\n    {\n        return sequencer.tryNext();\n    }\n\n    /**\n     * The same functionality as {@link RingBuffer#tryNext()}, but allows the caller to attempt\n     * to claim the next n sequences.\n     *\n     * @param n number of slots to claim\n     * @return sequence number of the highest slot claimed\n     * @throws InsufficientCapacityException if the necessary space in the ring buffer is not available\n     */\n    @Override\n    public long tryNext(final int n) throws InsufficientCapacityException\n    {\n        return sequencer.tryNext(n);\n    }\n\n    /**\n     * Sets the cursor to a specific sequence and returns the preallocated entry that is stored there.  This\n     * can cause a data race and should only be done in controlled circumstances, e.g. during initialisation.\n     *\n     * @param sequence The sequence to claim.\n     * @return The preallocated event.\n     */\n    public E claimAndGetPreallocated(final long sequence)\n    {\n        sequencer.claim(sequence);\n        return get(sequence);\n    }\n\n    /**\n     * Determines if the event for a given sequence is currently available.\n     *\n     * <p>Note that this does not guarantee that event will still be available\n     * on the next interaction with the RingBuffer. For example, it is not\n     * necessarily safe to write code like this:\n     *\n     * <pre>{@code\n     * if (ringBuffer.isAvailable(sequence))\n     * {\n     *     final E e = ringBuffer.get(sequence);\n     *     // ...do something with e\n     * }\n     * }</pre>\n     *\n     * <p>because there is a race between the reading thread and the writing thread.\n     *\n     * <p>This method will also return false when querying for sequences that are\n     * behind the ring buffer's wrap point.\n     *\n     * @param sequence The sequence to identify the entry.\n     * @return If the event published with the given sequence number is currently available.\n     */\n    public boolean isAvailable(final long sequence)\n    {\n        return sequencer.isAvailable(sequence);\n    }\n\n    /**\n     * Add the specified gating sequences to this instance of the Disruptor.  They will\n     * safely and atomically added to the list of gating sequences.\n     *\n     * @param gatingSequences The sequences to add.\n     */\n    public void addGatingSequences(final Sequence... gatingSequences)\n    {\n        sequencer.addGatingSequences(gatingSequences);\n    }\n\n    /**\n     * Get the minimum sequence value from all of the gating sequences\n     * added to this ringBuffer.\n     *\n     * @return The minimum gating sequence or the cursor sequence if\n     * no sequences have been added.\n     */\n    public long getMinimumGatingSequence()\n    {\n        return sequencer.getMinimumSequence();\n    }\n\n    /**\n     * Remove the specified sequence from this ringBuffer.\n     *\n     * @param sequence to be removed.\n     * @return <code>true</code> if this sequence was found, <code>false</code> otherwise.\n     */\n    public boolean removeGatingSequence(final Sequence sequence)\n    {\n        return sequencer.removeGatingSequence(sequence);\n    }\n\n    /**\n     * Create a new SequenceBarrier to be used by an EventProcessor to track which messages\n     * are available to be read from the ring buffer given a list of sequences to track.\n     *\n     * @param sequencesToTrack the additional sequences to track\n     * @return A sequence barrier that will track the specified sequences.\n     * @see SequenceBarrier\n     */\n    public SequenceBarrier newBarrier(final Sequence... sequencesToTrack)\n    {\n        return sequencer.newBarrier(sequencesToTrack);\n    }\n\n    /**\n     * Creates an event poller for this ring buffer gated on the supplied sequences.\n     *\n     * @param gatingSequences to be gated on.\n     * @return A poller that will gate on this ring buffer and the supplied sequences.\n     */\n    public EventPoller<E> newPoller(final Sequence... gatingSequences)\n    {\n        return sequencer.newPoller(this, gatingSequences);\n    }\n\n    /**\n     * Get the current cursor value for the ring buffer.  The actual value received\n     * will depend on the type of {@link Sequencer} that is being used.\n     *\n     * @see MultiProducerSequencer\n     * @see SingleProducerSequencer\n     */\n    @Override\n    public long getCursor()\n    {\n        return sequencer.getCursor();\n    }\n\n    /**\n     * The size of the buffer.\n     *\n     * @return size of buffer\n     */\n    @Override\n    public int getBufferSize()\n    {\n        return bufferSize;\n    }\n\n    /**\n     * Given specified <code>requiredCapacity</code> determines if that amount of space\n     * is available.  Note, you can not assume that if this method returns <code>true</code>\n     * that a call to {@link RingBuffer#next()} will not block.  Especially true if this\n     * ring buffer is set up to handle multiple producers.\n     *\n     * @param requiredCapacity The capacity to check for.\n     * @return <code>true</code> If the specified <code>requiredCapacity</code> is available\n     * <code>false</code> if not.\n     */\n    @Override\n    public boolean hasAvailableCapacity(final int requiredCapacity)\n    {\n        return sequencer.hasAvailableCapacity(requiredCapacity);\n    }\n\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslator)\n     */\n    @Override\n    public void publishEvent(final EventTranslator<E> translator)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslator)\n     */\n    @Override\n    public boolean tryPublishEvent(final EventTranslator<E> translator)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorOneArg, Object)\n     * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorOneArg, A)\n     */\n    @Override\n    public <A> void publishEvent(final EventTranslatorOneArg<E, A> translator, final A arg0)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, arg0);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorOneArg, Object)\n     * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorOneArg, A)\n     */\n    @Override\n    public <A> boolean tryPublishEvent(final EventTranslatorOneArg<E, A> translator, final A arg0)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, arg0);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorTwoArg, Object, Object)\n     * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorTwoArg, A, B)\n     */\n    @Override\n    public <A, B> void publishEvent(final EventTranslatorTwoArg<E, A, B> translator, final A arg0, final B arg1)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, arg0, arg1);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorTwoArg, Object, Object)\n     * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorTwoArg, A, B)\n     */\n    @Override\n    public <A, B> boolean tryPublishEvent(final EventTranslatorTwoArg<E, A, B> translator, final A arg0, final B arg1)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, arg0, arg1);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorThreeArg, Object, Object, Object)\n     * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorThreeArg, A, B, C)\n     */\n    @Override\n    public <A, B, C> void publishEvent(final EventTranslatorThreeArg<E, A, B, C> translator, final A arg0, final B arg1, final C arg2)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, arg0, arg1, arg2);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorThreeArg, Object, Object, Object)\n     * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorThreeArg, A, B, C)\n     */\n    @Override\n    public <A, B, C> boolean tryPublishEvent(final EventTranslatorThreeArg<E, A, B, C> translator, final A arg0, final B arg1, final C arg2)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, arg0, arg1, arg2);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object...)\n     */\n    @Override\n    public void publishEvent(final EventTranslatorVararg<E> translator, final Object... args)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, args);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object...)\n     */\n    @Override\n    public boolean tryPublishEvent(final EventTranslatorVararg<E> translator, final Object... args)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, args);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    @Override\n    public void publishEvents(final EventTranslator<E>[] translators)\n    {\n        publishEvents(translators, 0, translators.length);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslator[], int, int)\n     */\n    @Override\n    public void publishEvents(final EventTranslator<E>[] translators, final int batchStartsAt, final int batchSize)\n    {\n        checkBounds(translators, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translators, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    @Override\n    public boolean tryPublishEvents(final EventTranslator<E>[] translators)\n    {\n        return tryPublishEvents(translators, 0, translators.length);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslator[], int, int)\n     */\n    @Override\n    public boolean tryPublishEvents(final EventTranslator<E>[] translators, final int batchStartsAt, final int batchSize)\n    {\n        checkBounds(translators, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translators, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, A[])\n     */\n    @Override\n    public <A> void publishEvents(final EventTranslatorOneArg<E, A> translator, final A[] arg0)\n    {\n        publishEvents(translator, 0, arg0.length, arg0);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, A[])\n     */\n    @Override\n    public <A> void publishEvents(final EventTranslatorOneArg<E, A> translator, final int batchStartsAt, final int batchSize, final A[] arg0)\n    {\n        checkBounds(arg0, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, arg0, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, A[])\n     */\n    @Override\n    public <A> boolean tryPublishEvents(final EventTranslatorOneArg<E, A> translator, final A[] arg0)\n    {\n        return tryPublishEvents(translator, 0, arg0.length, arg0);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, A[])\n     */\n    @Override\n    public <A> boolean tryPublishEvents(\n            final EventTranslatorOneArg<E, A> translator, final int batchStartsAt, final int batchSize, final A[] arg0)\n    {\n        checkBounds(arg0, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, arg0, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, A[], B[])\n     */\n    @Override\n    public <A, B> void publishEvents(final EventTranslatorTwoArg<E, A, B> translator, final A[] arg0, final B[] arg1)\n    {\n        publishEvents(translator, 0, arg0.length, arg0, arg1);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, A[], B[])\n     */\n    @Override\n    public <A, B> void publishEvents(\n        final EventTranslatorTwoArg<E, A, B> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1)\n    {\n        checkBounds(arg0, arg1, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, arg0, arg1, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, A[], B[])\n     */\n    @Override\n    public <A, B> boolean tryPublishEvents(final EventTranslatorTwoArg<E, A, B> translator, final A[] arg0, final B[] arg1)\n    {\n        return tryPublishEvents(translator, 0, arg0.length, arg0, arg1);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, A[], B[])\n     */\n    @Override\n    public <A, B> boolean tryPublishEvents(\n        final EventTranslatorTwoArg<E, A, B> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1)\n    {\n        checkBounds(arg0, arg1, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, arg0, arg1, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> void publishEvents(final EventTranslatorThreeArg<E, A, B, C> translator, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        publishEvents(translator, 0, arg0.length, arg0, arg1, arg2);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> void publishEvents(\n        final EventTranslatorThreeArg<E, A, B, C> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        checkBounds(arg0, arg1, arg2, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, arg0, arg1, arg2, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> boolean tryPublishEvents(\n        final EventTranslatorThreeArg<E, A, B, C> translator, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        return tryPublishEvents(translator, 0, arg0.length, arg0, arg1, arg2);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> boolean tryPublishEvents(\n        final EventTranslatorThreeArg<E, A, B, C> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        checkBounds(arg0, arg1, arg2, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, arg0, arg1, arg2, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object[][])\n     */\n    @Override\n    public void publishEvents(final EventTranslatorVararg<E> translator, final Object[]... args)\n    {\n        publishEvents(translator, 0, args.length, args);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorVararg, int, int, java.lang.Object[][])\n     */\n    @Override\n    public void publishEvents(final EventTranslatorVararg<E> translator, final int batchStartsAt, final int batchSize, final Object[]... args)\n    {\n        checkBounds(batchStartsAt, batchSize, args);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, batchStartsAt, batchSize, finalSequence, args);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object[][])\n     */\n    @Override\n    public boolean tryPublishEvents(final EventTranslatorVararg<E> translator, final Object[]... args)\n    {\n        return tryPublishEvents(translator, 0, args.length, args);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorVararg, int, int, java.lang.Object[][])\n     */\n    @Override\n    public boolean tryPublishEvents(\n        final EventTranslatorVararg<E> translator, final int batchStartsAt, final int batchSize, final Object[]... args)\n    {\n        checkBounds(args, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, batchStartsAt, batchSize, finalSequence, args);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * Publish the specified sequence.  This action marks this particular\n     * message as being available to be read.\n     *\n     * @param sequence the sequence to publish.\n     */\n    @Override\n    public void publish(final long sequence)\n    {\n        sequencer.publish(sequence);\n    }\n\n    /**\n     * Publish the specified sequences.  This action marks these particular\n     * messages as being available to be read.\n     *\n     * @param lo the lowest sequence number to be published\n     * @param hi the highest sequence number to be published\n     * @see Sequencer#next(int)\n     */\n    @Override\n    public void publish(final long lo, final long hi)\n    {\n        sequencer.publish(lo, hi);\n    }\n\n    /**\n     * Get the remaining capacity for this ringBuffer.\n     *\n     * @return The number of slots remaining.\n     */\n    @Override\n    public long remainingCapacity()\n    {\n        return sequencer.remainingCapacity();\n    }\n\n    private void checkBounds(final EventTranslator<E>[] translators, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(translators, batchStartsAt, batchSize);\n    }\n\n    private void checkBatchSizing(final int batchStartsAt, final int batchSize)\n    {\n        if (batchStartsAt < 0 || batchSize < 0)\n        {\n            throw new IllegalArgumentException(\"Both batchStartsAt and batchSize must be positive but got: batchStartsAt \" + batchStartsAt + \" and batchSize \" + batchSize);\n        }\n        else if (batchSize > bufferSize)\n        {\n            throw new IllegalArgumentException(\"The ring buffer cannot accommodate \" + batchSize + \" it only has space for \" + bufferSize + \" entities.\");\n        }\n    }\n\n    private <A> void checkBounds(final A[] arg0, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(arg0, batchStartsAt, batchSize);\n    }\n\n    private <A, B> void checkBounds(final A[] arg0, final B[] arg1, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(arg0, batchStartsAt, batchSize);\n        batchOverRuns(arg1, batchStartsAt, batchSize);\n    }\n\n    private <A, B, C> void checkBounds(\n        final A[] arg0, final B[] arg1, final C[] arg2, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(arg0, batchStartsAt, batchSize);\n        batchOverRuns(arg1, batchStartsAt, batchSize);\n        batchOverRuns(arg2, batchStartsAt, batchSize);\n    }\n\n    private void checkBounds(final int batchStartsAt, final int batchSize, final Object[][] args)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(args, batchStartsAt, batchSize);\n    }\n\n    private <A> void batchOverRuns(final A[] arg0, final int batchStartsAt, final int batchSize)\n    {\n        if (batchStartsAt + batchSize > arg0.length)\n        {\n            throw new IllegalArgumentException(\n                \"A batchSize of: \" + batchSize +\n                    \" with batchStatsAt of: \" + batchStartsAt +\n                    \" will overrun the available number of arguments: \" + (arg0.length - batchStartsAt));\n        }\n    }\n\n    private void translateAndPublish(final EventTranslator<E> translator, final long sequence)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private <A> void translateAndPublish(final EventTranslatorOneArg<E, A> translator, final long sequence, final A arg0)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, arg0);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private <A, B> void translateAndPublish(final EventTranslatorTwoArg<E, A, B> translator, final long sequence, final A arg0, final B arg1)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, arg0, arg1);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private <A, B, C> void translateAndPublish(\n        final EventTranslatorThreeArg<E, A, B, C> translator, final long sequence,\n        final A arg0, final B arg1, final C arg2)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, arg0, arg1, arg2);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private void translateAndPublish(final EventTranslatorVararg<E> translator, final long sequence, final Object... args)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, args);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private void translateAndPublishBatch(\n        final EventTranslator<E>[] translators, final int batchStartsAt,\n        final int batchSize, final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                final EventTranslator<E> translator = translators[i];\n                translator.translateTo(get(sequence), sequence++);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private <A> void translateAndPublishBatch(\n        final EventTranslatorOneArg<E, A> translator, final A[] arg0,\n        final int batchStartsAt, final int batchSize, final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, arg0[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private <A, B> void translateAndPublishBatch(\n        final EventTranslatorTwoArg<E, A, B> translator, final A[] arg0,\n        final B[] arg1, final int batchStartsAt, final int batchSize,\n        final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, arg0[i], arg1[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private <A, B, C> void translateAndPublishBatch(\n        final EventTranslatorThreeArg<E, A, B, C> translator,\n        final A[] arg0, final B[] arg1, final C[] arg2, final int batchStartsAt,\n        final int batchSize, final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, arg0[i], arg1[i], arg2[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private void translateAndPublishBatch(\n        final EventTranslatorVararg<E> translator, final int batchStartsAt,\n        final int batchSize, final long finalSequence, final Object[][] args)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, args[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"RingBuffer{\" +\n            \"bufferSize=\" + bufferSize +\n            \", sequencer=\" + sequencer +\n            \"}\";\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/Sequence.java",
    "content": "package com.lmax.disruptor;\n\n\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.VarHandle;\n\nclass LhsPadding\n{\n    protected byte\n        p10, p11, p12, p13, p14, p15, p16, p17,\n        p20, p21, p22, p23, p24, p25, p26, p27,\n        p30, p31, p32, p33, p34, p35, p36, p37,\n        p40, p41, p42, p43, p44, p45, p46, p47,\n        p50, p51, p52, p53, p54, p55, p56, p57,\n        p60, p61, p62, p63, p64, p65, p66, p67,\n        p70, p71, p72, p73, p74, p75, p76, p77;\n}\n\nclass Value extends LhsPadding\n{\n    protected long value;\n}\n\nclass RhsPadding extends Value\n{\n    protected byte\n        p90, p91, p92, p93, p94, p95, p96, p97,\n        p100, p101, p102, p103, p104, p105, p106, p107,\n        p110, p111, p112, p113, p114, p115, p116, p117,\n        p120, p121, p122, p123, p124, p125, p126, p127,\n        p130, p131, p132, p133, p134, p135, p136, p137,\n        p140, p141, p142, p143, p144, p145, p146, p147,\n        p150, p151, p152, p153, p154, p155, p156, p157;\n}\n\n/**\n * Concurrent sequence class used for tracking the progress of\n * the ring buffer and event processors.  Support a number\n * of concurrent operations including CAS and order writes.\n *\n * <p>Also attempts to be more efficient with regards to false\n * sharing by adding padding around the volatile field.\n */\npublic class Sequence extends RhsPadding\n{\n    static final long INITIAL_VALUE = -1L;\n    private static final VarHandle VALUE_FIELD;\n\n    static\n    {\n        try\n        {\n            VALUE_FIELD = MethodHandles.lookup().in(Sequence.class)\n                    .findVarHandle(Sequence.class, \"value\", long.class);\n        }\n        catch (final Exception e)\n        {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Create a sequence initialised to -1.\n     */\n    public Sequence()\n    {\n        this(INITIAL_VALUE);\n    }\n\n    /**\n     * Create a sequence with a specified initial value.\n     *\n     * @param initialValue The initial value for this sequence.\n     */\n    public Sequence(final long initialValue)\n    {\n        VarHandle.releaseFence();\n        this.value = initialValue;\n    }\n\n    /**\n     * Perform a volatile read of this sequence's value.\n     *\n     * @return The current value of the sequence.\n     */\n    public long get()\n    {\n        long value = this.value;\n        VarHandle.acquireFence();\n        return value;\n    }\n\n    /**\n     * Perform an ordered write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * store.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void set(final long value)\n    {\n        VarHandle.releaseFence();\n        this.value = value;\n    }\n\n    /**\n     * Performs a volatile write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * write and a Store/Load barrier between this write and any\n     * subsequent volatile read.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void setVolatile(final long value)\n    {\n        VarHandle.releaseFence();\n        this.value = value;\n        VarHandle.fullFence();\n    }\n\n    /**\n     * Perform a compare and set operation on the sequence.\n     *\n     * @param expectedValue The expected current value.\n     * @param newValue      The value to update to.\n     * @return true if the operation succeeds, false otherwise.\n     */\n    public boolean compareAndSet(final long expectedValue, final long newValue)\n    {\n        return VALUE_FIELD.compareAndSet(this, expectedValue, newValue);\n    }\n\n    /**\n     * Atomically increment the sequence by one.\n     *\n     * @return The value after the increment\n     */\n    public long incrementAndGet()\n    {\n        return addAndGet(1);\n    }\n\n    /**\n     * Atomically add the supplied value.\n     *\n     * @param increment The value to add to the sequence.\n     * @return The value after the increment.\n     */\n    public long addAndGet(final long increment)\n    {\n        return (long) VALUE_FIELD.getAndAdd(this, increment) + increment;\n    }\n\n    /**\n     * Perform an atomic getAndAdd operation on the sequence.\n     *\n     * @param increment The value to add to the sequence.\n     * @return the value before increment\n     */\n    public long getAndAdd(final long increment)\n    {\n        return (long) VALUE_FIELD.getAndAdd(this, increment);\n    }\n\n    @Override\n    public String toString()\n    {\n        return Long.toString(get());\n    }\n}"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/SequenceBarrier.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n\n/**\n * Coordination barrier for tracking the cursor for publishers and sequence of\n * dependent {@link EventProcessor}s for processing a data structure\n */\npublic interface SequenceBarrier\n{\n    /**\n     * Wait for the given sequence to be available for consumption.\n     *\n     * @param sequence to wait for\n     * @return the sequence up to which is available\n     * @throws AlertException       if a status change has occurred for the Disruptor\n     * @throws InterruptedException if the thread needs awaking on a condition variable.\n     * @throws TimeoutException     if a timeout occurs while waiting for the supplied sequence.\n     */\n    long waitFor(long sequence) throws AlertException, InterruptedException, TimeoutException;\n\n    /**\n     * Get the current cursor value that can be read.\n     *\n     * @return value of the cursor for entries that have been published.\n     */\n    long getCursor();\n\n    /**\n     * The current alert status for the barrier.\n     *\n     * @return true if in alert otherwise false.\n     */\n    boolean isAlerted();\n\n    /**\n     * Alert the {@link EventProcessor}s of a status change and stay in this status until cleared.\n     */\n    void alert();\n\n    /**\n     * Clear the current alert status.\n     */\n    void clearAlert();\n\n    /**\n     * Check if an alert has been raised and throw an {@link AlertException} if it has.\n     *\n     * @throws AlertException if alert has been raised.\n     */\n    void checkAlert() throws AlertException;\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/SequenceGroup.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.util.Util;\n\nimport java.util.concurrent.atomic.AtomicReferenceFieldUpdater;\n\n/**\n * A {@link Sequence} group that can dynamically have {@link Sequence}s added and removed while being\n * thread safe.\n *\n * <p>The {@link SequenceGroup#get()} and {@link SequenceGroup#set(long)} methods are lock free and can be\n * concurrently be called with the {@link SequenceGroup#add(Sequence)} and {@link SequenceGroup#remove(Sequence)}.\n */\npublic final class SequenceGroup extends Sequence\n{\n    private static final AtomicReferenceFieldUpdater<SequenceGroup, Sequence[]> SEQUENCE_UPDATER =\n        AtomicReferenceFieldUpdater.newUpdater(SequenceGroup.class, Sequence[].class, \"sequences\");\n    private volatile Sequence[] sequences = new Sequence[0];\n\n    /**\n     * Default Constructor\n     */\n    public SequenceGroup()\n    {\n        super(-1);\n    }\n\n    /**\n     * Get the minimum sequence value for the group.\n     *\n     * @return the minimum sequence value for the group.\n     */\n    @Override\n    public long get()\n    {\n        return Util.getMinimumSequence(sequences);\n    }\n\n    /**\n     * Set all {@link Sequence}s in the group to a given value.\n     *\n     * @param value to set the group of sequences to.\n     */\n    @Override\n    public void set(final long value)\n    {\n        final Sequence[] sequences = this.sequences;\n        for (Sequence sequence : sequences)\n        {\n            sequence.set(value);\n        }\n    }\n\n    /**\n     * Add a {@link Sequence} into this aggregate.  This should only be used during\n     * initialisation.  Use {@link SequenceGroup#addWhileRunning(Cursored, Sequence)}\n     *\n     * @param sequence to be added to the aggregate.\n     * @see SequenceGroup#addWhileRunning(Cursored, Sequence)\n     */\n    public void add(final Sequence sequence)\n    {\n        Sequence[] oldSequences;\n        Sequence[] newSequences;\n        do\n        {\n            oldSequences = sequences;\n            final int oldSize = oldSequences.length;\n            newSequences = new Sequence[oldSize + 1];\n            System.arraycopy(oldSequences, 0, newSequences, 0, oldSize);\n            newSequences[oldSize] = sequence;\n        }\n        while (!SEQUENCE_UPDATER.compareAndSet(this, oldSequences, newSequences));\n    }\n\n    /**\n     * Remove the first occurrence of the {@link Sequence} from this aggregate.\n     *\n     * @param sequence to be removed from this aggregate.\n     * @return true if the sequence was removed otherwise false.\n     */\n    public boolean remove(final Sequence sequence)\n    {\n        return SequenceGroups.removeSequence(this, SEQUENCE_UPDATER, sequence);\n    }\n\n    /**\n     * Get the size of the group.\n     *\n     * @return the size of the group.\n     */\n    public int size()\n    {\n        return sequences.length;\n    }\n\n    /**\n     * Adds a sequence to the sequence group after threads have started to publish to\n     * the Disruptor.  It will set the sequences to cursor value of the ringBuffer\n     * just after adding them.  This should prevent any nasty rewind/wrapping effects.\n     *\n     * @param cursored The data structure that the owner of this sequence group will\n     *                 be pulling it's events from.\n     * @param sequence The sequence to add.\n     */\n    public void addWhileRunning(final Cursored cursored, final Sequence sequence)\n    {\n        SequenceGroups.addSequences(this, SEQUENCE_UPDATER, cursored, sequence);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/SequenceGroups.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport java.util.concurrent.atomic.AtomicReferenceFieldUpdater;\n\nimport static java.util.Arrays.copyOf;\n\n/**\n * Provides static methods for managing a {@link SequenceGroup} object.\n */\nclass SequenceGroups\n{\n    static <T> void addSequences(\n        final T holder,\n        final AtomicReferenceFieldUpdater<T, Sequence[]> updater,\n        final Cursored cursor,\n        final Sequence... sequencesToAdd)\n    {\n        long cursorSequence;\n        Sequence[] updatedSequences;\n        Sequence[] currentSequences;\n\n        do\n        {\n            currentSequences = updater.get(holder);\n            updatedSequences = copyOf(currentSequences, currentSequences.length + sequencesToAdd.length);\n            cursorSequence = cursor.getCursor();\n\n            int index = currentSequences.length;\n            for (Sequence sequence : sequencesToAdd)\n            {\n                sequence.set(cursorSequence);\n                updatedSequences[index++] = sequence;\n            }\n        }\n        while (!updater.compareAndSet(holder, currentSequences, updatedSequences));\n\n        cursorSequence = cursor.getCursor();\n        for (Sequence sequence : sequencesToAdd)\n        {\n            sequence.set(cursorSequence);\n        }\n    }\n\n    static <T> boolean removeSequence(\n        final T holder,\n        final AtomicReferenceFieldUpdater<T, Sequence[]> sequenceUpdater,\n        final Sequence sequence)\n    {\n        int numToRemove;\n        Sequence[] oldSequences;\n        Sequence[] newSequences;\n\n        do\n        {\n            oldSequences = sequenceUpdater.get(holder);\n\n            numToRemove = countMatching(oldSequences, sequence);\n\n            if (0 == numToRemove)\n            {\n                break;\n            }\n\n            final int oldSize = oldSequences.length;\n            newSequences = new Sequence[oldSize - numToRemove];\n\n            for (int i = 0, pos = 0; i < oldSize; i++)\n            {\n                final Sequence testSequence = oldSequences[i];\n                if (sequence != testSequence)\n                {\n                    newSequences[pos++] = testSequence;\n                }\n            }\n        }\n        while (!sequenceUpdater.compareAndSet(holder, oldSequences, newSequences));\n\n        return numToRemove != 0;\n    }\n\n    private static <T> int countMatching(final T[] values, final T toMatch)\n    {\n        int numToRemove = 0;\n        for (T value : values)\n        {\n            if (value == toMatch) // Specifically uses identity\n            {\n                numToRemove++;\n            }\n        }\n        return numToRemove;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/Sequenced.java",
    "content": "package com.lmax.disruptor;\n\n/**\n * Operations related to the sequencing of items in a {@link RingBuffer}.\n * See the two child interfaces, {@link Sequencer} and {@link EventSequencer} for more details.\n */\npublic interface Sequenced\n{\n    /**\n     * The capacity of the data structure to hold entries.\n     *\n     * @return the size of the RingBuffer.\n     */\n    int getBufferSize();\n\n    /**\n     * Has the buffer got capacity to allocate another sequence.  This is a concurrent\n     * method so the response should only be taken as an indication of available capacity.\n     *\n     * @param requiredCapacity in the buffer\n     * @return true if the buffer has the capacity to allocate the next sequence otherwise false.\n     */\n    boolean hasAvailableCapacity(int requiredCapacity);\n\n    /**\n     * Get the remaining capacity for this sequencer.\n     *\n     * @return The number of slots remaining.\n     */\n    long remainingCapacity();\n\n    /**\n     * Claim the next event in sequence for publishing.\n     *\n     * @return the claimed sequence value\n     */\n    long next();\n\n    /**\n     * Claim the next n events in sequence for publishing.  This is for batch event producing.  Using batch producing\n     * requires a little care and some math.\n     * <pre>\n     * int n = 10;\n     * long hi = sequencer.next(n);\n     * long lo = hi - (n - 1);\n     * for (long sequence = lo; sequence &lt;= hi; sequence++) {\n     *     // Do work.\n     * }\n     * sequencer.publish(lo, hi);\n     * </pre>\n     *\n     * @param n the number of sequences to claim\n     * @return the highest claimed sequence value\n     */\n    long next(int n);\n\n    /**\n     * Attempt to claim the next event in sequence for publishing.  Will return the\n     * number of the slot if there is at least <code>requiredCapacity</code> slots\n     * available.\n     *\n     * @return the claimed sequence value\n     * @throws InsufficientCapacityException thrown if there is no space available in the ring buffer.\n     */\n    long tryNext() throws InsufficientCapacityException;\n\n    /**\n     * Attempt to claim the next n events in sequence for publishing.  Will return the\n     * highest numbered slot if there is at least <code>requiredCapacity</code> slots\n     * available.  Have a look at {@link Sequencer#next()} for a description on how to\n     * use this method.\n     *\n     * @param n the number of sequences to claim\n     * @return the claimed sequence value\n     * @throws InsufficientCapacityException thrown if there is no space available in the ring buffer.\n     */\n    long tryNext(int n) throws InsufficientCapacityException;\n\n    /**\n     * Publishes a sequence. Call when the event has been filled.\n     *\n     * @param sequence the sequence to be published.\n     */\n    void publish(long sequence);\n\n    /**\n     * Batch publish sequences.  Called when all of the events have been filled.\n     *\n     * @param lo first sequence number to publish\n     * @param hi last sequence number to publish\n     */\n    void publish(long lo, long hi);\n}"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/Sequencer.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n/**\n * Coordinates claiming sequences for access to a data structure while tracking dependent {@link Sequence}s\n */\npublic interface Sequencer extends Cursored, Sequenced\n{\n    /**\n     * Set to -1 as sequence starting point\n     */\n    long INITIAL_CURSOR_VALUE = -1L;\n\n    /**\n     * Claim a specific sequence.  Only used if initialising the ring buffer to\n     * a specific value.\n     *\n     * @param sequence The sequence to initialise too.\n     */\n    void claim(long sequence);\n\n    /**\n     * Confirms if a sequence is published and the event is available for use; non-blocking.\n     *\n     * @param sequence of the buffer to check\n     * @return true if the sequence is available for use, false if not\n     */\n    boolean isAvailable(long sequence);\n\n    /**\n     * Add the specified gating sequences to this instance of the Disruptor.  They will\n     * safely and atomically added to the list of gating sequences.\n     *\n     * @param gatingSequences The sequences to add.\n     */\n    void addGatingSequences(Sequence... gatingSequences);\n\n    /**\n     * Remove the specified sequence from this sequencer.\n     *\n     * @param sequence to be removed.\n     * @return <code>true</code> if this sequence was found, <code>false</code> otherwise.\n     */\n    boolean removeGatingSequence(Sequence sequence);\n\n    /**\n     * Create a new SequenceBarrier to be used by an EventProcessor to track which messages\n     * are available to be read from the ring buffer given a list of sequences to track.\n     *\n     * @param sequencesToTrack All of the sequences that the newly constructed barrier will wait on.\n     * @return A sequence barrier that will track the specified sequences.\n     * @see SequenceBarrier\n     */\n    SequenceBarrier newBarrier(Sequence... sequencesToTrack);\n\n    /**\n     * Get the minimum sequence value from all of the gating sequences\n     * added to this ringBuffer.\n     *\n     * @return The minimum gating sequence or the cursor sequence if\n     * no sequences have been added.\n     */\n    long getMinimumSequence();\n\n    /**\n     * Get the highest sequence number that can be safely read from the ring buffer.  Depending\n     * on the implementation of the Sequencer this call may need to scan a number of values\n     * in the Sequencer.  The scan will range from nextSequence to availableSequence.  If\n     * there are no available values <code>&gt;= nextSequence</code> the return value will be\n     * <code>nextSequence - 1</code>.  To work correctly a consumer should pass a value that\n     * is 1 higher than the last sequence that was successfully processed.\n     *\n     * @param nextSequence      The sequence to start scanning from.\n     * @param availableSequence The sequence to scan to.\n     * @return The highest value that can be safely read, will be at least <code>nextSequence - 1</code>.\n     */\n    long getHighestPublishedSequence(long nextSequence, long availableSequence);\n\n    /**\n     * Creates an event poller from this sequencer\n     *\n     * @param provider from which events are drawn\n     * @param gatingSequences sequences to be gated on\n     * @param <T> the type of the event\n     * @return the event poller\n     */\n    <T> EventPoller<T> newPoller(DataProvider<T> provider, Sequence... gatingSequences);\n}"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/SimpleBatchRewindStrategy.java",
    "content": "package com.lmax.disruptor;\n\n/**\n * Batch rewind strategy that always rewinds\n */\npublic class SimpleBatchRewindStrategy implements BatchRewindStrategy\n{\n    @Override\n    public RewindAction handleRewindException(final RewindableException e, final int retriesAttempted)\n    {\n        return RewindAction.REWIND;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/SingleProducerSequencer.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.util.Util;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.locks.LockSupport;\n\nabstract class SingleProducerSequencerPad extends AbstractSequencer\n{\n    protected byte\n        p10, p11, p12, p13, p14, p15, p16, p17,\n        p20, p21, p22, p23, p24, p25, p26, p27,\n        p30, p31, p32, p33, p34, p35, p36, p37,\n        p40, p41, p42, p43, p44, p45, p46, p47,\n        p50, p51, p52, p53, p54, p55, p56, p57,\n        p60, p61, p62, p63, p64, p65, p66, p67,\n        p70, p71, p72, p73, p74, p75, p76, p77;\n\n    SingleProducerSequencerPad(final int bufferSize, final WaitStrategy waitStrategy)\n    {\n        super(bufferSize, waitStrategy);\n    }\n}\n\nabstract class SingleProducerSequencerFields extends SingleProducerSequencerPad\n{\n    SingleProducerSequencerFields(final int bufferSize, final WaitStrategy waitStrategy)\n    {\n        super(bufferSize, waitStrategy);\n    }\n\n    /**\n     * Set to -1 as sequence starting point\n     */\n    long nextValue = Sequence.INITIAL_VALUE;\n    long cachedValue = Sequence.INITIAL_VALUE;\n}\n\n/**\n * Coordinator for claiming sequences for access to a data structure while tracking dependent {@link Sequence}s.\n * Not safe for use from multiple threads as it does not implement any barriers.\n *\n * <p>* Note on {@link Sequencer#getCursor()}:  With this sequencer the cursor value is updated after the call\n * to {@link Sequencer#publish(long)} is made.\n */\n\npublic final class SingleProducerSequencer extends SingleProducerSequencerFields\n{\n    protected byte\n        p10, p11, p12, p13, p14, p15, p16, p17,\n        p20, p21, p22, p23, p24, p25, p26, p27,\n        p30, p31, p32, p33, p34, p35, p36, p37,\n        p40, p41, p42, p43, p44, p45, p46, p47,\n        p50, p51, p52, p53, p54, p55, p56, p57,\n        p60, p61, p62, p63, p64, p65, p66, p67,\n        p70, p71, p72, p73, p74, p75, p76, p77;\n\n    /**\n     * Construct a Sequencer with the selected wait strategy and buffer size.\n     *\n     * @param bufferSize   the size of the buffer that this will sequence over.\n     * @param waitStrategy for those waiting on sequences.\n     */\n    public SingleProducerSequencer(final int bufferSize, final WaitStrategy waitStrategy)\n    {\n        super(bufferSize, waitStrategy);\n    }\n\n    /**\n     * @see Sequencer#hasAvailableCapacity(int)\n     */\n    @Override\n    public boolean hasAvailableCapacity(final int requiredCapacity)\n    {\n        return hasAvailableCapacity(requiredCapacity, false);\n    }\n\n    private boolean hasAvailableCapacity(final int requiredCapacity, final boolean doStore)\n    {\n        long nextValue = this.nextValue;\n\n        long wrapPoint = (nextValue + requiredCapacity) - bufferSize;\n        long cachedGatingSequence = this.cachedValue;\n\n        if (wrapPoint > cachedGatingSequence || cachedGatingSequence > nextValue)\n        {\n            if (doStore)\n            {\n                cursor.setVolatile(nextValue);  // StoreLoad fence\n            }\n\n            long minSequence = Util.getMinimumSequence(gatingSequences, nextValue);\n            this.cachedValue = minSequence;\n\n            if (wrapPoint > minSequence)\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * @see Sequencer#next()\n     */\n    @Override\n    public long next()\n    {\n        return next(1);\n    }\n\n    /**\n     * @see Sequencer#next(int)\n     */\n    @Override\n    public long next(final int n)\n    {\n        assert sameThread() : \"Accessed by two threads - use ProducerType.MULTI!\";\n\n        if (n < 1 || n > bufferSize)\n        {\n            throw new IllegalArgumentException(\"n must be > 0 and < bufferSize\");\n        }\n\n        long nextValue = this.nextValue;\n\n        long nextSequence = nextValue + n;\n        long wrapPoint = nextSequence - bufferSize;\n        long cachedGatingSequence = this.cachedValue;\n\n        if (wrapPoint > cachedGatingSequence || cachedGatingSequence > nextValue)\n        {\n            cursor.setVolatile(nextValue);  // StoreLoad fence\n\n            long minSequence;\n            while (wrapPoint > (minSequence = Util.getMinimumSequence(gatingSequences, nextValue)))\n            {\n                LockSupport.parkNanos(1L); // TODO: Use waitStrategy to spin?\n            }\n\n            this.cachedValue = minSequence;\n        }\n\n        this.nextValue = nextSequence;\n\n        return nextSequence;\n    }\n\n    /**\n     * @see Sequencer#tryNext()\n     */\n    @Override\n    public long tryNext() throws InsufficientCapacityException\n    {\n        return tryNext(1);\n    }\n\n    /**\n     * @see Sequencer#tryNext(int)\n     */\n    @Override\n    public long tryNext(final int n) throws InsufficientCapacityException\n    {\n        if (n < 1)\n        {\n            throw new IllegalArgumentException(\"n must be > 0\");\n        }\n\n        if (!hasAvailableCapacity(n, true))\n        {\n            throw InsufficientCapacityException.INSTANCE;\n        }\n\n        long nextSequence = this.nextValue += n;\n\n        return nextSequence;\n    }\n\n    /**\n     * @see Sequencer#remainingCapacity()\n     */\n    @Override\n    public long remainingCapacity()\n    {\n        long nextValue = this.nextValue;\n\n        long consumed = Util.getMinimumSequence(gatingSequences, nextValue);\n        long produced = nextValue;\n        return getBufferSize() - (produced - consumed);\n    }\n\n    /**\n     * @see Sequencer#claim(long)\n     */\n    @Override\n    public void claim(final long sequence)\n    {\n        this.nextValue = sequence;\n    }\n\n    /**\n     * @see Sequencer#publish(long)\n     */\n    @Override\n    public void publish(final long sequence)\n    {\n        cursor.set(sequence);\n        waitStrategy.signalAllWhenBlocking();\n    }\n\n    /**\n     * @see Sequencer#publish(long, long)\n     */\n    @Override\n    public void publish(final long lo, final long hi)\n    {\n        publish(hi);\n    }\n\n    /**\n     * @see Sequencer#isAvailable(long)\n     */\n    @Override\n    public boolean isAvailable(final long sequence)\n    {\n        final long currentSequence = cursor.get();\n        return sequence <= currentSequence && sequence > currentSequence - bufferSize;\n    }\n\n    @Override\n    public long getHighestPublishedSequence(final long lowerBound, final long availableSequence)\n    {\n        return availableSequence;\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"SingleProducerSequencer{\" +\n                \"bufferSize=\" + bufferSize +\n                \", waitStrategy=\" + waitStrategy +\n                \", cursor=\" + cursor +\n                \", gatingSequences=\" + Arrays.toString(gatingSequences) +\n                '}';\n    }\n\n    private boolean sameThread()\n    {\n        return ProducerThreadAssertion.isSameThreadProducingTo(this);\n    }\n\n    /**\n     * Only used when assertions are enabled.\n     */\n    private static class ProducerThreadAssertion\n    {\n        /**\n         * Tracks the threads publishing to {@code SingleProducerSequencer}s to identify if more than one\n         * thread accesses any {@code SingleProducerSequencer}.\n         * I.e. it helps developers detect early if they use the wrong\n         * {@link com.lmax.disruptor.dsl.ProducerType}.\n         */\n        private static final Map<SingleProducerSequencer, Thread> PRODUCERS = new HashMap<>();\n\n        public static boolean isSameThreadProducingTo(final SingleProducerSequencer singleProducerSequencer)\n        {\n            synchronized (PRODUCERS)\n            {\n                final Thread currentThread = Thread.currentThread();\n                if (!PRODUCERS.containsKey(singleProducerSequencer))\n                {\n                    PRODUCERS.put(singleProducerSequencer, currentThread);\n                }\n                return PRODUCERS.get(singleProducerSequencer).equals(currentThread);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/SleepingWaitStrategy.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport java.util.concurrent.locks.LockSupport;\n\n/**\n * Sleeping strategy that initially spins, then uses a Thread.yield(), and\n * eventually sleep (<code>LockSupport.parkNanos(n)</code>) for the minimum\n * number of nanos the OS and JVM will allow while the\n * {@link com.lmax.disruptor.EventProcessor}s are waiting on a barrier.\n *\n * <p>This strategy is a good compromise between performance and CPU resource.\n * Latency spikes can occur after quiet periods.  It will also reduce the impact\n * on the producing thread as it will not need signal any conditional variables\n * to wake up the event handling thread.\n */\npublic final class SleepingWaitStrategy implements WaitStrategy\n{\n    private static final int SPIN_THRESHOLD = 100;\n    private static final int DEFAULT_RETRIES = 200;\n    private static final long DEFAULT_SLEEP = 100;\n\n    private final int retries;\n    private final long sleepTimeNs;\n\n    /**\n     * Provides a sleeping wait strategy with the default retry and sleep settings\n     */\n    public SleepingWaitStrategy()\n    {\n        this(DEFAULT_RETRIES, DEFAULT_SLEEP);\n    }\n\n    /**\n     * @param retries How many times the strategy should retry before sleeping\n     */\n    public SleepingWaitStrategy(final int retries)\n    {\n        this(retries, DEFAULT_SLEEP);\n    }\n\n    /**\n     * @param retries How many times the strategy should retry before sleeping\n     * @param sleepTimeNs How long the strategy should sleep, in nanoseconds\n     */\n    public SleepingWaitStrategy(final int retries, final long sleepTimeNs)\n    {\n        this.retries = retries;\n        this.sleepTimeNs = sleepTimeNs;\n    }\n\n    @Override\n    public long waitFor(\n        final long sequence, final Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier)\n        throws AlertException\n    {\n        long availableSequence;\n        int counter = retries;\n\n        while ((availableSequence = dependentSequence.get()) < sequence)\n        {\n            counter = applyWaitMethod(barrier, counter);\n        }\n\n        return availableSequence;\n    }\n\n    @Override\n    public void signalAllWhenBlocking()\n    {\n    }\n\n    private int applyWaitMethod(final SequenceBarrier barrier, final int counter)\n        throws AlertException\n    {\n        barrier.checkAlert();\n\n        if (counter > SPIN_THRESHOLD)\n        {\n            return counter - 1;\n        }\n        else if (counter > 0)\n        {\n            Thread.yield();\n            return counter - 1;\n        }\n        else\n        {\n            LockSupport.parkNanos(sleepTimeNs);\n        }\n\n        return counter;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/TimeoutBlockingWaitStrategy.java",
    "content": "package com.lmax.disruptor;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static com.lmax.disruptor.util.Util.awaitNanos;\n\n/**\n * Blocking strategy that uses a lock and condition variable for {@link EventProcessor}s waiting on a barrier.\n * However it will periodically wake up if it has been idle for specified period by throwing a\n * {@link TimeoutException}.  To make use of this, the event handler class should override\n * {@link EventHandler#onTimeout(long)}, which the {@link BatchEventProcessor} will call if the timeout occurs.\n *\n * <p>This strategy can be used when throughput and low-latency are not as important as CPU resource.\n */\npublic class TimeoutBlockingWaitStrategy implements WaitStrategy\n{\n    private final Object mutex = new Object();\n    private final long timeoutInNanos;\n\n    /**\n     * @param timeout how long to wait before waking up\n     * @param units the unit in which timeout is specified\n     */\n    public TimeoutBlockingWaitStrategy(final long timeout, final TimeUnit units)\n    {\n        timeoutInNanos = units.toNanos(timeout);\n    }\n\n    @Override\n    public long waitFor(\n        final long sequence,\n        final Sequence cursorSequence,\n        final Sequence dependentSequence,\n        final SequenceBarrier barrier)\n        throws AlertException, InterruptedException, TimeoutException\n    {\n        long timeoutNanos = timeoutInNanos;\n\n        long availableSequence;\n        if (cursorSequence.get() < sequence)\n        {\n            synchronized (mutex)\n            {\n                while (cursorSequence.get() < sequence)\n                {\n                    barrier.checkAlert();\n                    timeoutNanos = awaitNanos(mutex, timeoutNanos);\n                    if (timeoutNanos <= 0)\n                    {\n                        throw TimeoutException.INSTANCE;\n                    }\n                }\n            }\n        }\n\n        while ((availableSequence = dependentSequence.get()) < sequence)\n        {\n            barrier.checkAlert();\n        }\n\n        return availableSequence;\n    }\n\n    @Override\n    public void signalAllWhenBlocking()\n    {\n        synchronized (mutex)\n        {\n            mutex.notifyAll();\n        }\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"TimeoutBlockingWaitStrategy{\" +\n            \"mutex=\" + mutex +\n            \", timeoutInNanos=\" + timeoutInNanos +\n            '}';\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/TimeoutException.java",
    "content": "package com.lmax.disruptor;\n\n/**\n * Wait strategies may throw this Exception to inform callers that a\n * message has not been detected within a specific time window.\n * For efficiency, a single instance is provided.\n */\n@SuppressWarnings({\"serial\", \"lgtm[java/non-sync-override]\"})\npublic final class TimeoutException extends Exception\n{\n    /**\n     * The efficiency saving singleton instance\n     */\n    public static final TimeoutException INSTANCE = new TimeoutException();\n\n    private TimeoutException()\n    {\n        // Singleton\n    }\n\n    @Override\n    public Throwable fillInStackTrace()\n    {\n        return this;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/WaitStrategy.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n\n/**\n * Strategy employed for making {@link EventProcessor}s wait on a cursor {@link Sequence}.\n */\npublic interface WaitStrategy\n{\n    /**\n     * Wait for the given sequence to be available.  It is possible for this method to return a value\n     * less than the sequence number supplied depending on the implementation of the WaitStrategy.  A common\n     * use for this is to signal a timeout.  Any EventProcessor that is using a WaitStrategy to get notifications\n     * about message becoming available should remember to handle this case.  The {@link BatchEventProcessor} explicitly\n     * handles this case and will signal a timeout if required.\n     *\n     * @param sequence          to be waited on.\n     * @param cursor            the main sequence from ringbuffer. Wait/notify strategies will\n     *                          need this as it's the only sequence that is also notified upon update.\n     * @param dependentSequence on which to wait.\n     * @param barrier           the processor is waiting on.\n     * @return the sequence that is available which may be greater than the requested sequence.\n     * @throws AlertException       if the status of the Disruptor has changed.\n     * @throws InterruptedException if the thread is interrupted.\n     * @throws TimeoutException if a timeout occurs before waiting completes (not used by some strategies)\n     */\n    long waitFor(long sequence, Sequence cursor, Sequence dependentSequence, SequenceBarrier barrier)\n        throws AlertException, InterruptedException, TimeoutException;\n\n    /**\n     * Implementations should signal the waiting {@link EventProcessor}s that the cursor has advanced.\n     */\n    void signalAllWhenBlocking();\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/YieldingWaitStrategy.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n\n/**\n * Yielding strategy that uses a Thread.yield() for {@link com.lmax.disruptor.EventProcessor}s waiting on a barrier\n * after an initially spinning.\n *\n * <p>This strategy will use 100% CPU, but will more readily give up the CPU than a busy spin strategy if other threads\n * require CPU resource.\n */\npublic final class YieldingWaitStrategy implements WaitStrategy\n{\n    private static final int SPIN_TRIES = 100;\n\n    @Override\n    public long waitFor(\n        final long sequence, final Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier)\n        throws AlertException, InterruptedException\n    {\n        long availableSequence;\n        int counter = SPIN_TRIES;\n\n        while ((availableSequence = dependentSequence.get()) < sequence)\n        {\n            counter = applyWaitMethod(barrier, counter);\n        }\n\n        return availableSequence;\n    }\n\n    @Override\n    public void signalAllWhenBlocking()\n    {\n    }\n\n    private int applyWaitMethod(final SequenceBarrier barrier, final int counter)\n        throws AlertException\n    {\n        barrier.checkAlert();\n\n        if (0 == counter)\n        {\n            Thread.yield();\n        }\n        else\n        {\n            return counter - 1;\n        }\n\n        return counter;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/dsl/ConsumerInfo.java",
    "content": "package com.lmax.disruptor.dsl;\n\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\n\nimport java.util.concurrent.ThreadFactory;\n\ninterface ConsumerInfo\n{\n    Sequence[] getSequences();\n\n    SequenceBarrier getBarrier();\n\n    boolean isEndOfChain();\n\n    void start(ThreadFactory threadFactory);\n\n    void halt();\n\n    void markAsUsedInBarrier();\n\n    boolean isRunning();\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/dsl/ConsumerRepository.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.EventHandlerIdentity;\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.IdentityHashMap;\nimport java.util.Map;\nimport java.util.concurrent.ThreadFactory;\n\n/**\n * Provides a repository mechanism to associate {@link EventHandler}s with {@link EventProcessor}s\n */\nclass ConsumerRepository\n{\n    private final Map<EventHandlerIdentity, EventProcessorInfo> eventProcessorInfoByEventHandler =\n        new IdentityHashMap<>();\n    private final Map<Sequence, ConsumerInfo> eventProcessorInfoBySequence =\n        new IdentityHashMap<>();\n    private final Collection<ConsumerInfo> consumerInfos = new ArrayList<>();\n\n    public void add(\n        final EventProcessor eventprocessor,\n        final EventHandlerIdentity handlerIdentity,\n        final SequenceBarrier barrier)\n    {\n        final EventProcessorInfo consumerInfo = new EventProcessorInfo(eventprocessor, barrier);\n        eventProcessorInfoByEventHandler.put(handlerIdentity, consumerInfo);\n        eventProcessorInfoBySequence.put(eventprocessor.getSequence(), consumerInfo);\n        consumerInfos.add(consumerInfo);\n    }\n\n    public void add(final EventProcessor processor)\n    {\n        final EventProcessorInfo consumerInfo = new EventProcessorInfo(processor, null);\n        eventProcessorInfoBySequence.put(processor.getSequence(), consumerInfo);\n        consumerInfos.add(consumerInfo);\n    }\n\n    public void startAll(final ThreadFactory threadFactory)\n    {\n        consumerInfos.forEach(c -> c.start(threadFactory));\n    }\n\n    public void haltAll()\n    {\n        consumerInfos.forEach(ConsumerInfo::halt);\n    }\n\n    public boolean hasBacklog(final long cursor, final boolean includeStopped)\n    {\n        for (ConsumerInfo consumerInfo : consumerInfos)\n        {\n            if ((includeStopped || consumerInfo.isRunning()) && consumerInfo.isEndOfChain())\n            {\n                final Sequence[] sequences = consumerInfo.getSequences();\n                for (Sequence sequence : sequences)\n                {\n                    if (cursor > sequence.get())\n                    {\n                        return true;\n                    }\n                }\n            }\n        }\n\n        return false;\n    }\n\n    public EventProcessor getEventProcessorFor(final EventHandlerIdentity handlerIdentity)\n    {\n        final EventProcessorInfo eventprocessorInfo = getEventProcessorInfo(handlerIdentity);\n        if (eventprocessorInfo == null)\n        {\n            throw new IllegalArgumentException(\"The event handler \" + handlerIdentity + \" is not processing events.\");\n        }\n\n        return eventprocessorInfo.getEventProcessor();\n    }\n\n    public Sequence getSequenceFor(final EventHandlerIdentity handlerIdentity)\n    {\n        return getEventProcessorFor(handlerIdentity).getSequence();\n    }\n\n    public void unMarkEventProcessorsAsEndOfChain(final Sequence... barrierEventProcessors)\n    {\n        for (Sequence barrierEventProcessor : barrierEventProcessors)\n        {\n            getEventProcessorInfo(barrierEventProcessor).markAsUsedInBarrier();\n        }\n    }\n\n    public SequenceBarrier getBarrierFor(final EventHandlerIdentity handlerIdentity)\n    {\n        final ConsumerInfo consumerInfo = getEventProcessorInfo(handlerIdentity);\n        return consumerInfo != null ? consumerInfo.getBarrier() : null;\n    }\n\n    private EventProcessorInfo getEventProcessorInfo(final EventHandlerIdentity handlerIdentity)\n    {\n        return eventProcessorInfoByEventHandler.get(handlerIdentity);\n    }\n\n    private ConsumerInfo getEventProcessorInfo(final Sequence barrierEventProcessor)\n    {\n        return eventProcessorInfoBySequence.get(barrierEventProcessor);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/dsl/Disruptor.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl;\n\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.BatchRewindStrategy;\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.EventHandlerIdentity;\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.EventTranslator;\nimport com.lmax.disruptor.EventTranslatorOneArg;\nimport com.lmax.disruptor.EventTranslatorThreeArg;\nimport com.lmax.disruptor.EventTranslatorTwoArg;\nimport com.lmax.disruptor.ExceptionHandler;\nimport com.lmax.disruptor.RewindableEventHandler;\nimport com.lmax.disruptor.RewindableException;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.TimeoutException;\nimport com.lmax.disruptor.WaitStrategy;\nimport com.lmax.disruptor.util.Util;\n\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * A DSL-style API for setting up the disruptor pattern around a ring buffer\n * (aka the Builder pattern).\n *\n * <p>A simple example of setting up the disruptor with two event handlers that\n * must process events in order:\n *\n * <pre>\n * <code>Disruptor&lt;MyEvent&gt; disruptor = new Disruptor&lt;MyEvent&gt;(MyEvent.FACTORY, 32, Executors.newCachedThreadPool());\n * EventHandler&lt;MyEvent&gt; handler1 = new EventHandler&lt;MyEvent&gt;() { ... };\n * EventHandler&lt;MyEvent&gt; handler2 = new EventHandler&lt;MyEvent&gt;() { ... };\n * disruptor.handleEventsWith(handler1);\n * disruptor.after(handler1).handleEventsWith(handler2);\n *\n * RingBuffer ringBuffer = disruptor.start();</code>\n * </pre>\n *\n * @param <T> the type of event used.\n */\npublic class Disruptor<T>\n{\n    private final RingBuffer<T> ringBuffer;\n    private final ThreadFactory threadFactory;\n    private final ConsumerRepository consumerRepository = new ConsumerRepository();\n    private final AtomicBoolean started = new AtomicBoolean(false);\n    private ExceptionHandler<? super T> exceptionHandler = new ExceptionHandlerWrapper<>();\n\n    /**\n     * Create a new Disruptor. Will default to {@link com.lmax.disruptor.BlockingWaitStrategy} and\n     * {@link ProducerType}.MULTI\n     *\n     * @param eventFactory   the factory to create events in the ring buffer.\n     * @param ringBufferSize the size of the ring buffer.\n     * @param threadFactory  a {@link ThreadFactory} to create threads to for processors.\n     */\n    public Disruptor(final EventFactory<T> eventFactory, final int ringBufferSize, final ThreadFactory threadFactory)\n    {\n        this(RingBuffer.createMultiProducer(eventFactory, ringBufferSize), threadFactory);\n    }\n\n    /**\n     * Create a new Disruptor.\n     *\n     * @param eventFactory   the factory to create events in the ring buffer.\n     * @param ringBufferSize the size of the ring buffer, must be power of 2.\n     * @param threadFactory  a {@link ThreadFactory} to create threads for processors.\n     * @param producerType   the claim strategy to use for the ring buffer.\n     * @param waitStrategy   the wait strategy to use for the ring buffer.\n     */\n    public Disruptor(\n            final EventFactory<T> eventFactory,\n            final int ringBufferSize,\n            final ThreadFactory threadFactory,\n            final ProducerType producerType,\n            final WaitStrategy waitStrategy)\n    {\n        this(\n            RingBuffer.create(producerType, eventFactory, ringBufferSize, waitStrategy),\n            threadFactory);\n    }\n\n    /**\n     * Private constructor helper\n     */\n    private Disruptor(final RingBuffer<T> ringBuffer, final ThreadFactory threadFactory)\n    {\n        this.ringBuffer = ringBuffer;\n        this.threadFactory = threadFactory;\n    }\n\n    /**\n     * <p>Set up event handlers to handle events from the ring buffer. These handlers will process events\n     * as soon as they become available, in parallel.</p>\n     *\n     * <p>This method can be used as the start of a chain. For example if the handler <code>A</code> must\n     * process events before handler <code>B</code>:</p>\n     * <pre><code>dw.handleEventsWith(A).then(B);</code></pre>\n     *\n     * <p>This call is additive, but generally should only be called once when setting up the Disruptor instance</p>\n     *\n     * @param handlers the event handlers that will process events.\n     * @return a {@link EventHandlerGroup} that can be used to chain dependencies.\n     */\n    @SuppressWarnings(\"varargs\")\n    @SafeVarargs\n    public final EventHandlerGroup<T> handleEventsWith(final EventHandler<? super T>... handlers)\n    {\n        return createEventProcessors(new Sequence[0], handlers);\n    }\n\n    /**\n     * <p>Set up event handlers to handle events from the ring buffer. These handlers will process events\n     * as soon as they become available, in parallel.</p>\n     *\n     * <p>This method can be used as the start of a chain. For example if the handler <code>A</code> must\n     * process events before handler <code>B</code>:</p>\n     * <pre><code>dw.handleEventsWith(A).then(B);</code></pre>\n     *\n     * <p>This call is additive, but generally should only be called once when setting up the Disruptor instance</p>\n     *\n     * @param batchRewindStrategy a {@link BatchRewindStrategy} for customizing how to handle a {@link RewindableException}.\n     * @param handlers            the rewindable event handlers that will process events.\n     * @return a {@link EventHandlerGroup} that can be used to chain dependencies.\n     */\n    @SuppressWarnings(\"varargs\")\n    @SafeVarargs\n    public final EventHandlerGroup<T> handleEventsWith(final BatchRewindStrategy batchRewindStrategy,\n                                                       final RewindableEventHandler<? super T>... handlers)\n    {\n        return createEventProcessors(new Sequence[0], batchRewindStrategy, handlers);\n    }\n\n    /**\n     * <p>Set up custom event processors to handle events from the ring buffer. The Disruptor will\n     * automatically start these processors when {@link #start()} is called.</p>\n     *\n     * <p>This method can be used as the start of a chain. For example if the handler <code>A</code> must\n     * process events before handler <code>B</code>:</p>\n     * <pre><code>dw.handleEventsWith(A).then(B);</code></pre>\n     *\n     * <p>Since this is the start of the chain, the processor factories will always be passed an empty <code>Sequence</code>\n     * array, so the factory isn't necessary in this case. This method is provided for consistency with\n     * {@link EventHandlerGroup#handleEventsWith(EventProcessorFactory...)} and {@link EventHandlerGroup#then(EventProcessorFactory...)}\n     * which do have barrier sequences to provide.</p>\n     *\n     * <p>This call is additive, but generally should only be called once when setting up the Disruptor instance</p>\n     *\n     * @param eventProcessorFactories the event processor factories to use to create the event processors that will process events.\n     * @return a {@link EventHandlerGroup} that can be used to chain dependencies.\n     */\n    @SafeVarargs\n    public final EventHandlerGroup<T> handleEventsWith(final EventProcessorFactory<T>... eventProcessorFactories)\n    {\n        final Sequence[] barrierSequences = new Sequence[0];\n        return createEventProcessors(barrierSequences, eventProcessorFactories);\n    }\n\n    /**\n     * <p>Set up custom event processors to handle events from the ring buffer. The Disruptor will\n     * automatically start this processors when {@link #start()} is called.</p>\n     *\n     * <p>This method can be used as the start of a chain. For example if the processor <code>A</code> must\n     * process events before handler <code>B</code>:</p>\n     * <pre><code>dw.handleEventsWith(A).then(B);</code></pre>\n     *\n     * @param processors the event processors that will process events.\n     * @return a {@link EventHandlerGroup} that can be used to chain dependencies.\n     */\n    public EventHandlerGroup<T> handleEventsWith(final EventProcessor... processors)\n    {\n        for (final EventProcessor processor : processors)\n        {\n            consumerRepository.add(processor);\n        }\n\n        final Sequence[] sequences = Util.getSequencesFor(processors);\n\n        ringBuffer.addGatingSequences(sequences);\n\n        return new EventHandlerGroup<>(this, consumerRepository, sequences);\n    }\n\n\n    /**\n     * <p>Specify an exception handler to be used for any future event handlers.</p>\n     *\n     * <p>Note that only event handlers set up after calling this method will use the exception handler.</p>\n     *\n     * @param exceptionHandler the exception handler to use for any future {@link EventProcessor}.\n     * @deprecated This method only applies to future event handlers. Use setDefaultExceptionHandler instead which applies to existing and new event handlers.\n     */\n    @Deprecated\n    public void handleExceptionsWith(final ExceptionHandler<? super T> exceptionHandler)\n    {\n        this.exceptionHandler = exceptionHandler;\n    }\n\n    /**\n     * <p>Specify an exception handler to be used for event handlers and worker pools created by this Disruptor.</p>\n     *\n     * <p>The exception handler will be used by existing and future event handlers and worker pools created by this Disruptor instance.</p>\n     *\n     * @param exceptionHandler the exception handler to use.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public void setDefaultExceptionHandler(final ExceptionHandler<? super T> exceptionHandler)\n    {\n        checkNotStarted();\n        if (!(this.exceptionHandler instanceof ExceptionHandlerWrapper))\n        {\n            throw new IllegalStateException(\"setDefaultExceptionHandler can not be used after handleExceptionsWith\");\n        }\n        ((ExceptionHandlerWrapper<T>) this.exceptionHandler).switchTo(exceptionHandler);\n    }\n\n    /**\n     * Override the default exception handler for a specific handler.\n     * <pre>disruptorWizard.handleExceptionsIn(eventHandler).with(exceptionHandler);</pre>\n     *\n     * @param eventHandler the event handler to set a different exception handler for.\n     * @return an ExceptionHandlerSetting dsl object - intended to be used by chaining the with method call.\n     */\n    public ExceptionHandlerSetting<T> handleExceptionsFor(final EventHandlerIdentity eventHandler)\n    {\n        return new ExceptionHandlerSetting<>(eventHandler, consumerRepository);\n    }\n\n    /**\n     * <p>Create a group of event handlers to be used as a dependency.\n     * For example if the handler <code>A</code> must process events before handler <code>B</code>:</p>\n     *\n     * <pre><code>dw.after(A).handleEventsWith(B);</code></pre>\n     *\n     * @param handlers the event handlers, previously set up with {@link #handleEventsWith(EventHandler[])},\n     *                 that will form the barrier for subsequent handlers or processors.\n     * @return an {@link EventHandlerGroup} that can be used to setup a dependency barrier over the specified event handlers.\n     */\n    public final EventHandlerGroup<T> after(final EventHandlerIdentity... handlers)\n    {\n        final Sequence[] sequences = new Sequence[handlers.length];\n        for (int i = 0, handlersLength = handlers.length; i < handlersLength; i++)\n        {\n            sequences[i] = consumerRepository.getSequenceFor(handlers[i]);\n        }\n\n        return new EventHandlerGroup<>(this, consumerRepository, sequences);\n    }\n\n    /**\n     * Create a group of event processors to be used as a dependency.\n     *\n     * @param processors the event processors, previously set up with {@link #handleEventsWith(com.lmax.disruptor.EventProcessor...)},\n     *                   that will form the barrier for subsequent handlers or processors.\n     * @return an {@link EventHandlerGroup} that can be used to setup a {@link SequenceBarrier} over the specified event processors.\n     * @see #after(EventHandlerIdentity[])\n     */\n    public EventHandlerGroup<T> after(final EventProcessor... processors)\n    {\n        return new EventHandlerGroup<>(this, consumerRepository, Util.getSequencesFor(processors));\n    }\n\n    /**\n     * Publish an event to the ring buffer.\n     *\n     * @param eventTranslator the translator that will load data into the event.\n     */\n    public void publishEvent(final EventTranslator<T> eventTranslator)\n    {\n        ringBuffer.publishEvent(eventTranslator);\n    }\n\n    /**\n     * Publish an event to the ring buffer.\n     *\n     * @param <A>             Class of the user supplied argument.\n     * @param eventTranslator the translator that will load data into the event.\n     * @param arg             A single argument to load into the event\n     */\n    public <A> void publishEvent(final EventTranslatorOneArg<T, A> eventTranslator, final A arg)\n    {\n        ringBuffer.publishEvent(eventTranslator, arg);\n    }\n\n    /**\n     * Publish a batch of events to the ring buffer.\n     *\n     * @param <A>             Class of the user supplied argument.\n     * @param eventTranslator the translator that will load data into the event.\n     * @param arg             An array single arguments to load into the events. One Per event.\n     */\n    public <A> void publishEvents(final EventTranslatorOneArg<T, A> eventTranslator, final A[] arg)\n    {\n        ringBuffer.publishEvents(eventTranslator, arg);\n    }\n\n    /**\n     * Publish an event to the ring buffer.\n     *\n     * @param <A>             Class of the user supplied argument.\n     * @param <B>             Class of the user supplied argument.\n     * @param eventTranslator the translator that will load data into the event.\n     * @param arg0            The first argument to load into the event\n     * @param arg1            The second argument to load into the event\n     */\n    public <A, B> void publishEvent(final EventTranslatorTwoArg<T, A, B> eventTranslator, final A arg0, final B arg1)\n    {\n        ringBuffer.publishEvent(eventTranslator, arg0, arg1);\n    }\n\n    /**\n     * Publish an event to the ring buffer.\n     *\n     * @param eventTranslator the translator that will load data into the event.\n     * @param <A>             Class of the user supplied argument.\n     * @param <B>             Class of the user supplied argument.\n     * @param <C>             Class of the user supplied argument.\n     * @param arg0            The first argument to load into the event\n     * @param arg1            The second argument to load into the event\n     * @param arg2            The third argument to load into the event\n     */\n    public <A, B, C> void publishEvent(final EventTranslatorThreeArg<T, A, B, C> eventTranslator, final A arg0, final B arg1, final C arg2)\n    {\n        ringBuffer.publishEvent(eventTranslator, arg0, arg1, arg2);\n    }\n\n    /**\n     * <p>Starts the event processors and returns the fully configured ring buffer.</p>\n     *\n     * <p>The ring buffer is set up to prevent overwriting any entry that is yet to\n     * be processed by the slowest event processor.</p>\n     *\n     * <p>This method must only be called once after all event processors have been added.</p>\n     *\n     * @return the configured ring buffer.\n     */\n    public RingBuffer<T> start()\n    {\n        checkOnlyStartedOnce();\n        consumerRepository.startAll(threadFactory);\n\n        return ringBuffer;\n    }\n\n    /**\n     * Calls {@link com.lmax.disruptor.EventProcessor#halt()} on all of the event processors created via this disruptor.\n     */\n    public void halt()\n    {\n        consumerRepository.haltAll();\n    }\n\n    /**\n     * <p>Waits until all events currently in the disruptor have been processed by all event processors\n     * and then halts the processors.  It is critical that publishing to the ring buffer has stopped\n     * before calling this method, otherwise it may never return.</p>\n     *\n     * <p>This method will not shutdown the executor, nor will it await the final termination of the\n     * processor threads.</p>\n     */\n    public void shutdown()\n    {\n        try\n        {\n            shutdown(-1, TimeUnit.MILLISECONDS);\n        }\n        catch (final TimeoutException e)\n        {\n            exceptionHandler.handleOnShutdownException(e);\n        }\n    }\n\n    /**\n     * <p>Waits until all events currently in the disruptor have been processed by all event processors\n     * and then halts the processors.</p>\n     *\n     * <p>This method will not shutdown the executor, nor will it await the final termination of the\n     * processor threads.</p>\n     *\n     * @param timeout  the amount of time to wait for all events to be processed. <code>-1</code> will give an infinite timeout\n     * @param timeUnit the unit the timeOut is specified in\n     * @throws TimeoutException if a timeout occurs before shutdown completes.\n     */\n    public void shutdown(final long timeout, final TimeUnit timeUnit) throws TimeoutException\n    {\n        final long timeOutAt = System.nanoTime() + timeUnit.toNanos(timeout);\n        while (hasBacklog())\n        {\n            if (timeout >= 0 && System.nanoTime() > timeOutAt)\n            {\n                throw TimeoutException.INSTANCE;\n            }\n            // Busy spin\n        }\n        halt();\n    }\n\n    /**\n     * The {@link RingBuffer} used by this Disruptor.  This is useful for creating custom\n     * event processors if the behaviour of {@link BatchEventProcessor} is not suitable.\n     *\n     * @return the ring buffer used by this Disruptor.\n     */\n    public RingBuffer<T> getRingBuffer()\n    {\n        return ringBuffer;\n    }\n\n    /**\n     * Get the value of the cursor indicating the published sequence.\n     *\n     * @return value of the cursor for events that have been published.\n     */\n    public long getCursor()\n    {\n        return ringBuffer.getCursor();\n    }\n\n    /**\n     * The capacity of the data structure to hold entries.\n     *\n     * @return the size of the RingBuffer.\n     * @see com.lmax.disruptor.Sequencer#getBufferSize()\n     */\n    public long getBufferSize()\n    {\n        return ringBuffer.getBufferSize();\n    }\n\n    /**\n     * Get the event for a given sequence in the RingBuffer.\n     *\n     * @param sequence for the event.\n     * @return event for the sequence.\n     * @see RingBuffer#get(long)\n     */\n    public T get(final long sequence)\n    {\n        return ringBuffer.get(sequence);\n    }\n\n    /**\n     * Get the {@link SequenceBarrier} used by a specific handler. Note that the {@link SequenceBarrier}\n     * may be shared by multiple event handlers.\n     *\n     * @param handler the handler to get the barrier for.\n     * @return the SequenceBarrier used by <i>handler</i>.\n     */\n    public SequenceBarrier getBarrierFor(final EventHandlerIdentity handler)\n    {\n        return consumerRepository.getBarrierFor(handler);\n    }\n\n    /**\n     * Gets the sequence value for the specified event handlers.\n     *\n     * @param handler eventHandler to get the sequence for.\n     * @return eventHandler's sequence\n     */\n    public long getSequenceValueFor(final EventHandlerIdentity handler)\n    {\n        return consumerRepository.getSequenceFor(handler).get();\n    }\n\n    /**\n     * Confirms if all messages have been consumed by all event processors\n     */\n    private boolean hasBacklog()\n    {\n        final long cursor = ringBuffer.getCursor();\n\n        return consumerRepository.hasBacklog(cursor, false);\n    }\n\n    /**\n     * Checks if disruptor has been started\n     *\n     * @return true when start has been called on this instance; otherwise false\n     */\n    public boolean hasStarted()\n    {\n        return started.get();\n    }\n\n    EventHandlerGroup<T> createEventProcessors(\n            final Sequence[] barrierSequences,\n            final EventHandler<? super T>[] eventHandlers)\n    {\n        checkNotStarted();\n\n        final Sequence[] processorSequences = new Sequence[eventHandlers.length];\n        final SequenceBarrier barrier = ringBuffer.newBarrier(barrierSequences);\n\n        for (int i = 0, eventHandlersLength = eventHandlers.length; i < eventHandlersLength; i++)\n        {\n            final EventHandler<? super T> eventHandler = eventHandlers[i];\n\n            final BatchEventProcessor<T> batchEventProcessor =\n                    new BatchEventProcessorBuilder().build(ringBuffer, barrier, eventHandler);\n\n            if (exceptionHandler != null)\n            {\n                batchEventProcessor.setExceptionHandler(exceptionHandler);\n            }\n\n            consumerRepository.add(batchEventProcessor, eventHandler, barrier);\n            processorSequences[i] = batchEventProcessor.getSequence();\n        }\n\n        updateGatingSequencesForNextInChain(barrierSequences, processorSequences);\n\n        return new EventHandlerGroup<>(this, consumerRepository, processorSequences);\n    }\n\n    EventHandlerGroup<T> createEventProcessors(\n            final Sequence[] barrierSequences,\n            final BatchRewindStrategy batchRewindStrategy,\n            final RewindableEventHandler<? super T>[] eventHandlers)\n    {\n        checkNotStarted();\n\n        final Sequence[] processorSequences = new Sequence[eventHandlers.length];\n        final SequenceBarrier barrier = ringBuffer.newBarrier(barrierSequences);\n\n        for (int i = 0, eventHandlersLength = eventHandlers.length; i < eventHandlersLength; i++)\n        {\n            final RewindableEventHandler<? super T> eventHandler = eventHandlers[i];\n\n            final BatchEventProcessor<T> batchEventProcessor =\n                    new BatchEventProcessorBuilder().build(ringBuffer, barrier, eventHandler, batchRewindStrategy);\n\n            if (exceptionHandler != null)\n            {\n                batchEventProcessor.setExceptionHandler(exceptionHandler);\n            }\n\n            consumerRepository.add(batchEventProcessor, eventHandler, barrier);\n            processorSequences[i] = batchEventProcessor.getSequence();\n        }\n\n        updateGatingSequencesForNextInChain(barrierSequences, processorSequences);\n\n        return new EventHandlerGroup<>(this, consumerRepository, processorSequences);\n    }\n\n    private void updateGatingSequencesForNextInChain(final Sequence[] barrierSequences, final Sequence[] processorSequences)\n    {\n        if (processorSequences.length > 0)\n        {\n            ringBuffer.addGatingSequences(processorSequences);\n            for (final Sequence barrierSequence : barrierSequences)\n            {\n                ringBuffer.removeGatingSequence(barrierSequence);\n            }\n            consumerRepository.unMarkEventProcessorsAsEndOfChain(barrierSequences);\n        }\n    }\n\n    EventHandlerGroup<T> createEventProcessors(\n            final Sequence[] barrierSequences, final EventProcessorFactory<T>[] processorFactories)\n    {\n        final EventProcessor[] eventProcessors = new EventProcessor[processorFactories.length];\n        for (int i = 0; i < processorFactories.length; i++)\n        {\n            eventProcessors[i] = processorFactories[i].createEventProcessor(ringBuffer, barrierSequences);\n        }\n\n        return handleEventsWith(eventProcessors);\n    }\n\n    private void checkNotStarted()\n    {\n        if (started.get())\n        {\n            throw new IllegalStateException(\"All event handlers must be added before calling starts.\");\n        }\n    }\n\n    private void checkOnlyStartedOnce()\n    {\n        if (!started.compareAndSet(false, true))\n        {\n            throw new IllegalStateException(\"Disruptor.start() must only be called once.\");\n        }\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"Disruptor{\" +\n                \"ringBuffer=\" + ringBuffer +\n                \", started=\" + started +\n                \", threadFactory=\" + threadFactory +\n                '}';\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/dsl/EventHandlerGroup.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl;\n\nimport com.lmax.disruptor.BatchRewindStrategy;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.RewindableEventHandler;\nimport com.lmax.disruptor.RewindableException;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\n\nimport java.util.Arrays;\n\n/**\n * A group of {@link EventProcessor}s used as part of the {@link Disruptor}.\n *\n * @param <T> the type of entry used by the event processors.\n */\npublic class EventHandlerGroup<T>\n{\n    private final Disruptor<T> disruptor;\n    private final ConsumerRepository consumerRepository;\n    private final Sequence[] sequences;\n\n    EventHandlerGroup(\n        final Disruptor<T> disruptor,\n        final ConsumerRepository consumerRepository,\n        final Sequence[] sequences)\n    {\n        this.disruptor = disruptor;\n        this.consumerRepository = consumerRepository;\n        this.sequences = Arrays.copyOf(sequences, sequences.length);\n    }\n\n    /**\n     * Create a new event handler group that combines the consumers in this group with <code>otherHandlerGroup</code>.\n     *\n     * @param otherHandlerGroup the event handler group to combine.\n     * @return a new EventHandlerGroup combining the existing and new consumers into a single dependency group.\n     */\n    public EventHandlerGroup<T> and(final EventHandlerGroup<T> otherHandlerGroup)\n    {\n        final Sequence[] combinedSequences = new Sequence[this.sequences.length + otherHandlerGroup.sequences.length];\n        System.arraycopy(this.sequences, 0, combinedSequences, 0, this.sequences.length);\n        System.arraycopy(\n            otherHandlerGroup.sequences, 0,\n            combinedSequences, this.sequences.length, otherHandlerGroup.sequences.length);\n        return new EventHandlerGroup<>(disruptor, consumerRepository, combinedSequences);\n    }\n\n    /**\n     * Create a new event handler group that combines the handlers in this group with <code>processors</code>.\n     *\n     * @param processors the processors to combine.\n     * @return a new EventHandlerGroup combining the existing and new processors into a single dependency group.\n     */\n    public EventHandlerGroup<T> and(final EventProcessor... processors)\n    {\n        Sequence[] combinedSequences = new Sequence[sequences.length + processors.length];\n\n        for (int i = 0; i < processors.length; i++)\n        {\n            consumerRepository.add(processors[i]);\n            combinedSequences[i] = processors[i].getSequence();\n        }\n        System.arraycopy(sequences, 0, combinedSequences, processors.length, sequences.length);\n\n        return new EventHandlerGroup<>(disruptor, consumerRepository, combinedSequences);\n    }\n\n    /**\n     * <p>Set up batch handlers to consume events from the ring buffer. These handlers will only process events\n     * after every {@link EventProcessor} in this group has processed the event.</p>\n     *\n     * <p>This method is generally used as part of a chain. For example if the handler <code>A</code> must\n     * process events before handler <code>B</code>:</p>\n     *\n     * <pre><code>dw.handleEventsWith(A).then(B);</code></pre>\n     *\n     * @param handlers the batch handlers that will process events.\n     * @return a {@link EventHandlerGroup} that can be used to set up a event processor barrier over the created event processors.\n     */\n    @SafeVarargs\n    public final EventHandlerGroup<T> then(final EventHandler<? super T>... handlers)\n    {\n        return handleEventsWith(handlers);\n    }\n\n    /**\n     * <p>Set up batch handlers to consume events from the ring buffer. These handlers will only process events\n     * after every {@link EventProcessor} in this group has processed the event.</p>\n     *\n     * <p>This method is generally used as part of a chain. For example if the handler <code>A</code> must\n     * process events before handler <code>B</code>:</p>\n     *\n     * <pre><code>dw.handleEventsWith(A).then(B);</code></pre>\n     *\n     * @param batchRewindStrategy a {@link BatchRewindStrategy} for customizing how to handle a {@link RewindableException}.\n     * @param handlers            the rewindable event handlers that will process events.\n     * @return a {@link EventHandlerGroup} that can be used to set up a event processor barrier over the created event processors.\n     */\n    @SafeVarargs\n    public final EventHandlerGroup<T> then(final BatchRewindStrategy batchRewindStrategy,\n                                           final RewindableEventHandler<? super T>... handlers)\n    {\n        return handleEventsWith(batchRewindStrategy, handlers);\n    }\n\n    /**\n     * <p>Set up custom event processors to handle events from the ring buffer. The Disruptor will\n     * automatically start these processors when {@link Disruptor#start()} is called.</p>\n     *\n     * <p>This method is generally used as part of a chain. For example if the handler <code>A</code> must\n     * process events before handler <code>B</code>:</p>\n     *\n     * @param eventProcessorFactories the event processor factories to use to create the event processors that will process events.\n     * @return a {@link EventHandlerGroup} that can be used to chain dependencies.\n     */\n    @SafeVarargs\n    public final EventHandlerGroup<T> then(final EventProcessorFactory<T>... eventProcessorFactories)\n    {\n        return handleEventsWith(eventProcessorFactories);\n    }\n\n    /**\n     * <p>Set up batch handlers to handle events from the ring buffer. These handlers will only process events\n     * after every {@link EventProcessor} in this group has processed the event.</p>\n     *\n     * <p>This method is generally used as part of a chain. For example if <code>A</code> must\n     * process events before <code>B</code>:</p>\n     *\n     * <pre><code>dw.after(A).handleEventsWith(B);</code></pre>\n     *\n     * @param handlers the batch handlers that will process events.\n     * @return a {@link EventHandlerGroup} that can be used to set up a event processor barrier over the created event processors.\n     */\n    @SafeVarargs\n    public final EventHandlerGroup<T> handleEventsWith(final EventHandler<? super T>... handlers)\n    {\n        return disruptor.createEventProcessors(sequences, handlers);\n    }\n\n    /**\n     * <p>Set up batch handlers to handle events from the ring buffer. These handlers will only process events\n     * after every {@link EventProcessor} in this group has processed the event.</p>\n     *\n     * <p>This method is generally used as part of a chain. For example if <code>A</code> must\n     * process events before <code>B</code>:</p>\n     *\n     * <pre><code>dw.after(A).handleEventsWith(B);</code></pre>\n     *\n     * @param batchRewindStrategy a {@link BatchRewindStrategy} for customizing how to handle a {@link RewindableException}.\n     * @param handlers            the rewindable event handlers that will process events.\n     * @return a {@link EventHandlerGroup} that can be used to set up a event processor barrier over the created event processors.\n     */\n    @SafeVarargs\n    public final EventHandlerGroup<T> handleEventsWith(final BatchRewindStrategy batchRewindStrategy,\n                                                       final RewindableEventHandler<? super T>... handlers)\n    {\n        return disruptor.createEventProcessors(sequences, batchRewindStrategy, handlers);\n    }\n\n    /**\n     * <p>Set up custom event processors to handle events from the ring buffer. The Disruptor will\n     * automatically start these processors when {@link Disruptor#start()} is called.</p>\n     *\n     * <p>This method is generally used as part of a chain. For example if <code>A</code> must\n     * process events before <code>B</code>:</p>\n     *\n     * <pre><code>dw.after(A).handleEventsWith(B);</code></pre>\n     *\n     * @param eventProcessorFactories the event processor factories to use to create the event processors that will process events.\n     * @return a {@link EventHandlerGroup} that can be used to chain dependencies.\n     */\n    @SafeVarargs\n    public final EventHandlerGroup<T> handleEventsWith(final EventProcessorFactory<T>... eventProcessorFactories)\n    {\n        return disruptor.createEventProcessors(sequences, eventProcessorFactories);\n    }\n\n    /**\n     * Create a dependency barrier for the processors in this group.\n     * This allows custom event processors to have dependencies on\n     * {@link com.lmax.disruptor.BatchEventProcessor}s created by the disruptor.\n     *\n     * @return a {@link SequenceBarrier} including all the processors in this group.\n     */\n    public SequenceBarrier asSequenceBarrier()\n    {\n        return disruptor.getRingBuffer().newBarrier(sequences);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/dsl/EventProcessorFactory.java",
    "content": "package com.lmax.disruptor.dsl;\n\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.Sequence;\n\n/**\n * A factory interface to make it possible to include custom event processors in a chain:\n *\n * <pre><code>\n * disruptor.handleEventsWith(handler1).then((ringBuffer, barrierSequences) -&gt; new CustomEventProcessor(ringBuffer, barrierSequences));\n * </code></pre>\n *\n * @param <T> implementation storing the data for sharing during exchange or parallel coordination of an event.\n */\npublic interface EventProcessorFactory<T>\n{\n    /**\n     * Create a new event processor that gates on <code>barrierSequences</code>.\n     *\n     * @param ringBuffer the ring buffer to receive events from.\n     * @param barrierSequences the sequences to gate on\n     * @return a new EventProcessor that gates on <code>barrierSequences</code> before processing events\n     */\n    EventProcessor createEventProcessor(RingBuffer<T> ringBuffer, Sequence[] barrierSequences);\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/dsl/EventProcessorInfo.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl;\n\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\n\nimport java.util.concurrent.ThreadFactory;\n\n/**\n * Wrapper class to tie together a particular event processing stage</p>\n *\n * <p><p>Tracks the event processor instance, the event handler instance, and sequence barrier which the stage is attached to.</p>\n *\n */\nclass EventProcessorInfo implements ConsumerInfo\n{\n    private final EventProcessor eventprocessor;\n    private final SequenceBarrier barrier;\n    private boolean endOfChain = true;\n\n    EventProcessorInfo(final EventProcessor eventprocessor, final SequenceBarrier barrier)\n    {\n        this.eventprocessor = eventprocessor;\n        this.barrier = barrier;\n    }\n\n    public EventProcessor getEventProcessor()\n    {\n        return eventprocessor;\n    }\n\n    @Override\n    public Sequence[] getSequences()\n    {\n        return new Sequence[]{eventprocessor.getSequence()};\n    }\n\n    @Override\n    public SequenceBarrier getBarrier()\n    {\n        return barrier;\n    }\n\n    @Override\n    public boolean isEndOfChain()\n    {\n        return endOfChain;\n    }\n\n    @Override\n    public void start(final ThreadFactory threadFactory)\n    {\n        final Thread thread = threadFactory.newThread(eventprocessor);\n        if (null == thread)\n        {\n            throw new RuntimeException(\"Failed to create thread to run: \" + eventprocessor);\n        }\n\n        thread.start();\n    }\n\n    @Override\n    public void halt()\n    {\n        eventprocessor.halt();\n    }\n\n    /**\n     *\n     */\n    @Override\n    public void markAsUsedInBarrier()\n    {\n        endOfChain = false;\n    }\n\n    @Override\n    public boolean isRunning()\n    {\n        return eventprocessor.isRunning();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerSetting.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl;\n\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.EventHandlerIdentity;\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.ExceptionHandler;\n\n/**\n * A support class used as part of setting an exception handler for a specific event handler.\n * For example:\n * <pre><code>disruptorWizard.handleExceptionsIn(eventHandler).with(exceptionHandler);</code></pre>\n *\n * @param <T> the type of event being handled.\n */\npublic class ExceptionHandlerSetting<T>\n{\n    private final EventHandlerIdentity handlerIdentity;\n    private final ConsumerRepository consumerRepository;\n\n    ExceptionHandlerSetting(\n        final EventHandlerIdentity handlerIdentity,\n        final ConsumerRepository consumerRepository)\n    {\n        this.handlerIdentity = handlerIdentity;\n        this.consumerRepository = consumerRepository;\n    }\n\n    /**\n     * Specify the {@link ExceptionHandler} to use with the event handler.\n     *\n     * @param exceptionHandler the exception handler to use.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public void with(final ExceptionHandler<? super T> exceptionHandler)\n    {\n        final EventProcessor eventProcessor = consumerRepository.getEventProcessorFor(handlerIdentity);\n        if (eventProcessor instanceof BatchEventProcessor)\n        {\n            ((BatchEventProcessor<T>) eventProcessor).setExceptionHandler(exceptionHandler);\n            consumerRepository.getBarrierFor(handlerIdentity).alert();\n        }\n        else\n        {\n            throw new RuntimeException(\n                \"EventProcessor: \" + eventProcessor + \" is not a BatchEventProcessor \" +\n                \"and does not support exception handlers\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerWrapper.java",
    "content": "package com.lmax.disruptor.dsl;\n\nimport com.lmax.disruptor.ExceptionHandler;\nimport com.lmax.disruptor.ExceptionHandlers;\n\n/**\n * A mutable exception handler wrapper\n * @param <T> The data type of the underlying {@link com.lmax.disruptor.RingBuffer}\n */\npublic class ExceptionHandlerWrapper<T> implements ExceptionHandler<T>\n{\n    private ExceptionHandler<? super T> delegate;\n\n    /**\n     * Switch to a different exception handler\n     * @param exceptionHandler the exception handler to use from now on\n     */\n    public void switchTo(final ExceptionHandler<? super T> exceptionHandler)\n    {\n        this.delegate = exceptionHandler;\n    }\n\n    @Override\n    public void handleEventException(final Throwable ex, final long sequence, final T event)\n    {\n        getExceptionHandler().handleEventException(ex, sequence, event);\n    }\n\n    @Override\n    public void handleOnStartException(final Throwable ex)\n    {\n        getExceptionHandler().handleOnStartException(ex);\n    }\n\n    @Override\n    public void handleOnShutdownException(final Throwable ex)\n    {\n        getExceptionHandler() .handleOnShutdownException(ex);\n    }\n\n    private ExceptionHandler<? super T> getExceptionHandler()\n    {\n        ExceptionHandler<? super T> handler = delegate;\n        return handler == null ? ExceptionHandlers.defaultHandler() : handler;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/dsl/ProducerType.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl;\n\n/**\n * Defines producer types to support creation of RingBuffer with correct sequencer and publisher.\n */\npublic enum ProducerType\n{\n    /**\n     * Create a RingBuffer with a single event publisher to the RingBuffer\n     */\n    SINGLE,\n\n    /**\n     * Create a RingBuffer supporting multiple event publishers to the one RingBuffer\n     */\n    MULTI\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/dsl/package-info.java",
    "content": "/**\n * A DSL-style API for setting up the disruptor pattern around a ring buffer.\n *\n * <h2>Example code</h2>\n * <pre>{@code\n * // Specify the size of the ring buffer, must be power of 2.\n *  int bufferSize = 1024;\n *\n *  // Construct the Disruptor\n *  Disruptor<LongEvent> disruptor = new Disruptor<>(LongEvent::new, bufferSize, DaemonThreadFactory.INSTANCE);\n *\n *  // Connect the handler\n *  disruptor.handleEventsWith((event, sequence, endOfBatch) -> System.out.println(\"Event: \" + event));\n *\n *  // Start the Disruptor, starts all threads running\n *  disruptor.start();\n *\n *  // Get the ring buffer from the Disruptor to be used for publishing.\n *  RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();\n *\n *  ByteBuffer bb = ByteBuffer.allocate(8);\n *  for (long l = 0; true; l++)\n *  {\n *      bb.putLong(0, l);\n *      ringBuffer.publishEvent((event, sequence, buffer) -> event.set(buffer.getLong(0)), bb);\n *      Thread.sleep(1000);\n *  }\n * }</pre>\n */\npackage com.lmax.disruptor.dsl;"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/package-info.java",
    "content": "/**\n * The Disruptor is a concurrent programming framework for exchanging and coordinating work as a continuous series of events.\n * It can be used as an alternative to wiring processing stages together via queues.\n * The Disruptor design has the characteristics of generating significantly less garbage than queues and separates the\n * concurrency concerns so non-locking algorithms can be employed resulting in greater scalability and performance.\n *\n * <p>It works on the principle of having a number of stages that are each single threaded with local state and memory.\n * No global memory exists and all communication is achieved by passing messages/state via managed ring buffers.\n *\n * <p>Almost any graph or pipeline structure can be composed via one or more Disruptor patterns.\n *\n * <h2>UniCast a series of items between 1 publisher and 1 EventProcessor.</h2>\n *\n * <pre>{@code\n *                                           track to prevent wrap\n *                                           +------------------+\n *                                           |                  |\n *                                           |                  v\n * +----+    +-----+            +----+    +====+    +====+   +-----+\n * | P1 |--->| EP1 |            | P1 |--->| RB |<---| SB |   | EP1 |\n * +----+    +-----+            +----+    +====+    +====+   +-----+\n *                                   claim      get    ^        |\n *                                                     |        |\n *                                                     +--------+\n *                                                       waitFor\n * }</pre>\n *\n * <h2>Sequence a series of messages from multiple publishers</h2>\n * <pre>{@code\n *                                          track to prevent wrap\n *                                          +--------------------+\n *                                          |                    |\n *                                          |                    v\n * +----+                       +----+    +====+    +====+    +-----+\n * | P1 |-------+               | P1 |--->| RB |<---| SB |    | EP1 |\n * +----+       |               +----+    +====+    +====+    +-----+\n *              v                           ^   get    ^         |\n * +----+    +-----+            +----+      |          |         |\n * | P2 |--->| EP1 |            | P2 |------+          +---------+\n * +----+    +-----+            +----+      |            waitFor\n *              ^                           |\n * +----+       |               +----+      |\n * | P3 |-------+               | P3 |------+\n * +----+                       +----+\n * }</pre>\n *\n * <h2>Pipeline a series of messages</h2>\n * <pre>{@code\n *                           +----+    +-----+    +-----+    +-----+\n *                           | P1 |--->| EP1 |--->| EP2 |--->| EP3 |\n *                           +----+    +-----+    +-----+    +-----+\n *\n *\n *\n *                           track to prevent wrap\n *              +----------------------------------------------------------------+\n *              |                                                                |\n *              |                                                                v\n * +----+    +====+    +=====+    +-----+    +=====+    +-----+    +=====+    +-----+\n * | P1 |--->| RB |    | SB1 |<---| EP1 |<---| SB2 |<---| EP2 |<---| SB3 |<---| EP3 |\n * +----+    +====+    +=====+    +-----+    +=====+    +-----+    +=====+    +-----+\n *      claim   ^  get    |   waitFor           |   waitFor           |  waitFor\n *              |         |                     |                     |\n *              +---------+---------------------+---------------------+\n * }</pre>\n *\n * <h2>Multicast a series of messages to multiple EventProcessors</h2>\n * <pre>{@code\n *           +-----+                                        track to prevent wrap\n *    +----->| EP1 |                        +--------------------+----------+----------+\n *    |      +-----+                        |                    |          |          |\n *    |                                     |                    v          v          v\n * +----+    +-----+            +----+    +====+    +====+    +-----+    +-----+    +-----+\n * | P1 |--->| EP2 |            | P1 |--->| RB |<---| SB |    | EP1 |    | EP2 |    | EP3 |\n * +----+    +-----+            +----+    +====+    +====+    +-----+    +-----+    +-----+\n *    |                              claim      get    ^         |          |          |\n *    |      +-----+                                   |         |          |          |\n *    +----->| EP3 |                                   +---------+----------+----------+\n *           +-----+                                                 waitFor\n * }</pre>\n *\n * <h2>Replicate a message then fold back the results</h2>\n * <pre>{@code\n *           +-----+                               track to prevent wrap\n *    +----->| EP1 |-----+                   +-------------------------------+\n *    |      +-----+     |                   |                               |\n *    |                  v                   |                               v\n * +----+             +-----+   +----+    +====+               +=====+    +-----+\n * | P1 |             | EP3 |   | P1 |--->| RB |<--------------| SB2 |<---| EP3 |\n * +----+             +-----+   +----+    +====+               +=====+    +-----+\n *    |                  ^           claim   ^  get               |   waitFor\n *    |      +-----+     |                   |                    |\n *    +----->| EP2 |-----+                +=====+    +-----+      |\n *           +-----+                      | SB1 |<---| EP1 |<-----+\n *                                        +=====+    +-----+      |\n *                                           ^                    |\n *                                           |       +-----+      |\n *                                           +-------| EP2 |<-----+\n *                                          waitFor  +-----+\n * }</pre>\n *\n * <h2>Code Example</h2>\n * <pre>{@code\n * // Event holder for data to be exchanged\n * public final class ValueEvent\n * {\n *     private long value;\n *\n *     public long getValue()\n *     {\n *         return value;\n *     }\n *\n *     public void setValue(final long value)\n *     {\n *         this.value = value;\n *     }\n *\n *     public final static EventFactory<ValueEvent> EVENT_FACTORY = new EventFactory<ValueEvent>()\n *     {\n *         public ValueEvent newInstance()\n *         {\n *             return new ValueEvent();\n *         }\n *     };\n * }\n *\n * // Callback handler which can be implemented by EventProcessors\n * final EventHandler<ValueEvent> eventHandler = new EventHandler<ValueEvent>()\n * {\n *     public void onEvent(final ValueEvent event, final long sequence, final boolean endOfBatch)\n *         throws Exception\n *     {\n *         // process a new event as it becomes available.\n *     }\n * };\n *\n * RingBuffer<ValueEvent> ringBuffer =\n *     new RingBuffer<ValueEvent>(ValueEvent.EVENT_FACTORY,\n *                                new SingleThreadedClaimStrategy(BUFFER_SIZE),\n *                                new SleepingWaitStrategy());\n *\n * SequenceBarrier<ValueEvent> sequenceBarrier = ringBuffer.newBarrier();\n * BatchEventProcessor<ValueEvent> batchProcessor = new BatchEventProcessor<ValueEvent>(sequenceBarrier, eventHandler);\n * ringBuffer.setGatingSequences(batchProcessor.getSequence());\n *\n * // Each processor runs on a separate thread\n * EXECUTOR.submit(batchProcessor);\n *\n * // Publishers claim events in sequence\n * long sequence = ringBuffer.next();\n * ValueEvent event = ringBuffer.get(sequence);\n *\n * event.setValue(1234);\n *\n * // publish the event so it is available to EventProcessors\n * ringBuffer.publish(sequence);\n * }</pre>\n */\npackage com.lmax.disruptor;"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/util/DaemonThreadFactory.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.util;\n\nimport java.util.concurrent.ThreadFactory;\n\n/**\n * Access to a ThreadFactory instance. All threads are created with setDaemon(true).\n */\npublic enum DaemonThreadFactory implements ThreadFactory\n{\n    /**\n     * The singleton instance\n     */\n    INSTANCE;\n\n    @Override\n    public Thread newThread(final Runnable r)\n    {\n        Thread t = new Thread(r);\n        t.setDaemon(true);\n        return t;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/util/ThreadHints.java",
    "content": "/*  Copyright 2016 Gil Tene\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lmax.disruptor.util;\n\n/**\n * This class captures possible hints that may be used by some\n * runtimes to improve code performance. It is intended to capture hinting\n * behaviours that are implemented in or anticipated to be spec'ed under the\n * {@link java.lang.Thread} class in some Java SE versions, but missing in prior\n * versions.\n * @deprecated Use Thread.onSpinWait() directly. This class previously existed to accommodate\n * Java versions which do not have Thread.onSpinWait().\n */\n@Deprecated\npublic final class ThreadHints\n{\n\n    private ThreadHints()\n    {\n    }\n\n    /**\n     * Indicates that the caller is momentarily unable to progress, until the\n     * occurrence of one or more actions on the part of other activities.  By\n     * invoking this method within each iteration of a spin-wait loop construct,\n     * the calling thread indicates to the runtime that it is busy-waiting. The runtime\n     * may take action to improve the performance of invoking spin-wait loop constructions.\n     *\n     * @deprecated Use Thread.onSpinWait() directly. This method previously existed to accommodate\n     * Java versions which do not have Thread.onSpinWait().\n     */\n    @Deprecated\n    public static void onSpinWait()\n    {\n        Thread.onSpinWait();\n    }\n}"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/util/Util.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.util;\n\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.Sequence;\n\n/**\n * Set of common functions used by the Disruptor.\n */\npublic final class Util\n{\n    private static final int ONE_MILLISECOND_IN_NANOSECONDS = 1_000_000;\n\n    /**\n     * Calculate the next power of 2, greater than or equal to x.\n     *\n     * <p>From Hacker's Delight, Chapter 3, Harry S. Warren Jr.\n     *\n     * @param x Value to round up\n     * @return The next power of 2 from x inclusive\n     */\n    public static int ceilingNextPowerOfTwo(final int x)\n    {\n        return 1 << (Integer.SIZE - Integer.numberOfLeadingZeros(x - 1));\n    }\n\n    /**\n     * Get the minimum sequence from an array of {@link com.lmax.disruptor.Sequence}s.\n     *\n     * @param sequences to compare.\n     * @return the minimum sequence found or Long.MAX_VALUE if the array is empty.\n     */\n    public static long getMinimumSequence(final Sequence[] sequences)\n    {\n        return getMinimumSequence(sequences, Long.MAX_VALUE);\n    }\n\n    /**\n     * Get the minimum sequence from an array of {@link com.lmax.disruptor.Sequence}s.\n     *\n     * @param sequences to compare.\n     * @param minimum   an initial default minimum.  If the array is empty this value will be\n     *                  returned.\n     * @return the smaller of minimum sequence value found in {@code sequences} and {@code minimum};\n     * {@code minimum} if {@code sequences} is empty\n     */\n    public static long getMinimumSequence(final Sequence[] sequences, final long minimum)\n    {\n        long minimumSequence = minimum;\n        for (int i = 0, n = sequences.length; i < n; i++)\n        {\n            long value = sequences[i].get();\n            minimumSequence = Math.min(minimumSequence, value);\n        }\n\n        return minimumSequence;\n    }\n\n    /**\n     * Get an array of {@link Sequence}s for the passed {@link EventProcessor}s.\n     *\n     * @param processors for which to get the sequences\n     * @return the array of {@link Sequence}s\n     */\n    public static Sequence[] getSequencesFor(final EventProcessor... processors)\n    {\n        Sequence[] sequences = new Sequence[processors.length];\n        for (int i = 0; i < sequences.length; i++)\n        {\n            sequences[i] = processors[i].getSequence();\n        }\n\n        return sequences;\n    }\n\n    /**\n     * Calculate the log base 2 of the supplied integer, essentially reports the location\n     * of the highest bit.\n     *\n     * @param value Positive value to calculate log2 for.\n     * @return The log2 value\n     */\n    public static int log2(final int value)\n    {\n        if (value < 1)\n        {\n            throw new IllegalArgumentException(\"value must be a positive number\");\n        }\n        return Integer.SIZE - Integer.numberOfLeadingZeros(value) - 1;\n    }\n\n    /**\n     * @param mutex The object to wait on\n     * @param timeoutNanos The number of nanoseconds to wait for\n     * @return the number of nanoseconds waited (approximately)\n     * @throws InterruptedException if the underlying call to wait is interrupted\n     */\n    public static long awaitNanos(final Object mutex, final long timeoutNanos) throws InterruptedException\n    {\n        long millis = timeoutNanos / ONE_MILLISECOND_IN_NANOSECONDS;\n        long nanos = timeoutNanos % ONE_MILLISECOND_IN_NANOSECONDS;\n\n        long t0 = System.nanoTime();\n        mutex.wait(millis, (int) nanos);\n        long t1 = System.nanoTime();\n\n        return timeoutNanos - (t1 - t0);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lmax/disruptor/util/package-info.java",
    "content": "/**\n * Utility classes\n */\npackage com.lmax.disruptor.util;"
  },
  {
    "path": "src/main/java/module-info.java",
    "content": "module com.lmax.disruptor {\n    exports com.lmax.disruptor;\n    exports com.lmax.disruptor.dsl;\n    exports com.lmax.disruptor.util;\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/AbstractPerfTestDisruptor.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n\npublic abstract class AbstractPerfTestDisruptor\n{\n    public static final int RUNS = 7;\n\n    protected void testImplementations()\n        throws Exception\n    {\n        final int availableProcessors = Runtime.getRuntime().availableProcessors();\n        if (getRequiredProcessorCount() > availableProcessors)\n        {\n            System.out.print(\"*** Warning ***: your system has insufficient processors to execute the test efficiently. \");\n            System.out.println(\"Processors required = \" + getRequiredProcessorCount() + \" available = \" + availableProcessors);\n        }\n\n        PerfTestContext[] contexts = new PerfTestContext[RUNS];\n\n        System.out.println(\"Starting Disruptor tests\");\n        for (int i = 0; i < RUNS; i++)\n        {\n            System.gc();\n            PerfTestContext context = runDisruptorPass();\n            contexts[i] = context;\n            System.out.format(\"Run %d, Disruptor=%,d ops/sec BatchPercent=%.2f%% AverageBatchSize=%,d\\n\",\n                    i, context.getDisruptorOps(), context.getBatchPercent() * 100, (long) context.getAverageBatchSize());\n        }\n    }\n\n    public static void printResults(final String className, final PerfTestContext[] contexts, final long[] queueOps)\n    {\n        for (int i = 0; i < RUNS; i++)\n        {\n            PerfTestContext context = contexts[i];\n            System.out.format(\"%s run %d: BlockingQueue=%,d Disruptor=%,d ops/sec BatchPercent=%,d AverageBatchSize=%,d\\n\",\n                              className, Integer.valueOf(i), Long.valueOf(queueOps[i]), Long.valueOf(context.getDisruptorOps()),\n                              Double.valueOf(context.getBatchPercent()), Double.valueOf(context.getAverageBatchSize()));\n        }\n    }\n\n    protected abstract int getRequiredProcessorCount();\n\n    protected abstract PerfTestContext runDisruptorPass() throws Exception;\n}\n\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/AbstractPerfTestQueue.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\n\npublic abstract class AbstractPerfTestQueue\n{\n    public static final int RUNS = 7;\n\n    protected void testImplementations()\n        throws Exception\n    {\n        final int availableProcessors = Runtime.getRuntime().availableProcessors();\n        if (getRequiredProcessorCount() > availableProcessors)\n        {\n            System.out.print(\n                \"*** Warning ***: your system has insufficient processors to execute the test efficiently. \");\n            System.out.println(\n                \"Processors required = \" + getRequiredProcessorCount() + \" available = \" + availableProcessors);\n        }\n\n        long[] queueOps = new long[RUNS];\n\n        System.out.println(\"Starting Queue tests\");\n        for (int i = 0; i < RUNS; i++)\n        {\n            System.gc();\n            queueOps[i] = runQueuePass();\n            System.out.format(\"Run %d, BlockingQueue=%,d ops/sec%n\", i, Long.valueOf(queueOps[i]));\n        }\n    }\n\n    public static void printResults(final String className, final long[] disruptorOps, final long[] queueOps)\n    {\n        for (int i = 0; i < RUNS; i++)\n        {\n            System.out.format(\n                \"%s run %d: BlockingQueue=%,d Disruptor=%,d ops/sec\\n\",\n                className, Integer.valueOf(i), Long.valueOf(queueOps[i]), Long.valueOf(disruptorOps[i]));\n        }\n    }\n\n    protected abstract int getRequiredProcessorCount();\n\n    protected abstract long runQueuePass() throws Exception;\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/PerfTestContext.java",
    "content": "package com.lmax.disruptor;\n\npublic class PerfTestContext\n{\n    private long disruptorOps;\n    private long batchesProcessedCount;\n    private long iterations;\n\n    public PerfTestContext()\n    {\n    }\n\n    public long getDisruptorOps()\n    {\n        return disruptorOps;\n    }\n\n    public void setDisruptorOps(final long disruptorOps)\n    {\n        this.disruptorOps = disruptorOps;\n    }\n\n    public long getBatchesProcessedCount()\n    {\n        return batchesProcessedCount;\n    }\n\n    public double getBatchPercent()\n    {\n        if (batchesProcessedCount == 0)\n        {\n            return 0;\n        }\n        return 1 - (double) batchesProcessedCount / iterations;\n    }\n\n    public double getAverageBatchSize()\n    {\n        if (batchesProcessedCount == 0)\n        {\n            return -1;\n        }\n        return (double) iterations / batchesProcessedCount;\n    }\n\n    public void setBatchData(final long batchesProcessedCount, final long iterations)\n    {\n        this.batchesProcessedCount = batchesProcessedCount;\n        this.iterations = iterations;\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/immutable/Constants.java",
    "content": "package com.lmax.disruptor.immutable;\n\npublic class Constants\n{\n    public static final long ITERATIONS = 1000 * 1000 * 100L;\n    public static final int SIZE = 1 << 20;\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/immutable/CustomPerformanceTest.java",
    "content": "package com.lmax.disruptor.immutable;\n\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.SingleProducerSequencer;\nimport com.lmax.disruptor.YieldingWaitStrategy;\n\nimport java.util.concurrent.locks.LockSupport;\n\npublic class CustomPerformanceTest\n{\n    private final CustomRingBuffer<SimpleEvent> ringBuffer;\n\n    public CustomPerformanceTest()\n    {\n        ringBuffer =\n                new CustomRingBuffer<>(new SingleProducerSequencer(Constants.SIZE, new YieldingWaitStrategy()));\n    }\n\n    public void run()\n    {\n        try\n        {\n            doRun();\n        }\n        catch (InterruptedException e)\n        {\n            e.printStackTrace();\n        }\n    }\n\n    private void doRun() throws InterruptedException\n    {\n        BatchEventProcessor<?> batchEventProcessor = ringBuffer.createHandler(new SimpleEventHandler());\n\n        Thread t = new Thread(batchEventProcessor);\n        t.start();\n\n        long iterations = Constants.ITERATIONS;\n        for (long l = 0; l < iterations; l++)\n        {\n            SimpleEvent e = new SimpleEvent(l, l, l, l);\n            ringBuffer.put(e);\n        }\n\n        while (batchEventProcessor.getSequence().get() != iterations - 1)\n        {\n            LockSupport.parkNanos(1);\n        }\n\n        batchEventProcessor.halt();\n        t.join();\n    }\n\n    public static void main(final String[] args)\n    {\n        new CustomPerformanceTest().run();\n    }\n\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/immutable/CustomRingBuffer.java",
    "content": "package com.lmax.disruptor.immutable;\n\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.DataProvider;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.Sequencer;\n\npublic class CustomRingBuffer<T> implements DataProvider<EventAccessor<T>>, EventAccessor<T>\n{\n    private static final class AccessorEventHandler<T> implements EventHandler<EventAccessor<T>>\n    {\n        private final EventHandler<T> handler;\n\n        private AccessorEventHandler(final EventHandler<T> handler)\n        {\n            this.handler = handler;\n        }\n\n        @Override\n        public void onEvent(final EventAccessor<T> accessor, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            this.handler.onEvent(accessor.take(sequence), sequence, endOfBatch);\n        }\n\n        @Override\n        public void onShutdown()\n        {\n            handler.onShutdown();\n        }\n\n        @Override\n        public void onStart()\n        {\n            handler.onStart();\n        }\n    }\n\n    private final Sequencer sequencer;\n    private final Object[] buffer;\n    private final int mask;\n\n    public CustomRingBuffer(final Sequencer sequencer)\n    {\n        this.sequencer = sequencer;\n        buffer = new Object[sequencer.getBufferSize()];\n        mask = sequencer.getBufferSize() - 1;\n    }\n\n    private int index(final long sequence)\n    {\n        return (int) sequence & mask;\n    }\n\n    public void put(final T e)\n    {\n        long next = sequencer.next();\n        buffer[index(next)] = e;\n        sequencer.publish(next);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public T take(final long sequence)\n    {\n        int index = index(sequence);\n\n        T t = (T) buffer[index];\n        buffer[index] = null;\n\n        return t;\n    }\n\n    @Override\n    public EventAccessor<T> get(final long sequence)\n    {\n        return this;\n    }\n\n    public BatchEventProcessor<EventAccessor<T>> createHandler(final EventHandler<T> handler)\n    {\n        BatchEventProcessor<EventAccessor<T>> processor =\n                new BatchEventProcessorBuilder().build(\n                        this,\n                        sequencer.newBarrier(),\n                        new AccessorEventHandler<>(handler));\n        sequencer.addGatingSequences(processor.getSequence());\n\n        return processor;\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/immutable/EventAccessor.java",
    "content": "package com.lmax.disruptor.immutable;\n\npublic interface EventAccessor<T>\n{\n    T take(long sequence);\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/immutable/EventHolder.java",
    "content": "package com.lmax.disruptor.immutable;\n\nimport com.lmax.disruptor.EventFactory;\n\npublic class EventHolder\n{\n\n    public static final EventFactory<EventHolder> FACTORY = EventHolder::new;\n\n    public SimpleEvent event;\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/immutable/EventHolderHandler.java",
    "content": "package com.lmax.disruptor.immutable;\n\nimport com.lmax.disruptor.EventHandler;\n\npublic class EventHolderHandler implements EventHandler<EventHolder>\n{\n    private final EventHandler<SimpleEvent> delegate;\n\n    public EventHolderHandler(final EventHandler<SimpleEvent> delegate)\n    {\n        this.delegate = delegate;\n    }\n\n    @Override\n    public void onEvent(final EventHolder holder, final long sequence, final boolean endOfBatch) throws Exception\n    {\n        delegate.onEvent(holder.event, sequence, endOfBatch);\n        holder.event = null;\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/immutable/SimpleEvent.java",
    "content": "package com.lmax.disruptor.immutable;\n\npublic class SimpleEvent\n{\n    private final long id;\n    private final long v1;\n    private final long v2;\n    private final long v3;\n\n    public SimpleEvent(final long id, final long v1, final long v2, final long v3)\n    {\n        this.id = id;\n        this.v1 = v1;\n        this.v2 = v2;\n        this.v3 = v3;\n    }\n\n    public long getCounter()\n    {\n        return v1;\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"SimpleEvent [id=\" + id + \", v1=\" + v1 + \", v2=\" + v2 + \", v3=\" + v3 + \"]\";\n    }\n}"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/immutable/SimpleEventHandler.java",
    "content": "package com.lmax.disruptor.immutable;\n\nimport com.lmax.disruptor.EventHandler;\n\npublic class SimpleEventHandler implements EventHandler<SimpleEvent>\n{\n    public long counter;\n\n    @Override\n    public void onEvent(final SimpleEvent arg0, final long arg1, final boolean arg2) throws Exception\n    {\n        counter += arg0.getCounter();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/immutable/SimplePerformanceTest.java",
    "content": "package com.lmax.disruptor.immutable;\n\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.EventTranslatorOneArg;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.YieldingWaitStrategy;\n\nimport java.util.concurrent.locks.LockSupport;\n\npublic class SimplePerformanceTest\n{\n    private final RingBuffer<EventHolder> ringBuffer;\n    private final EventHolderHandler eventHolderHandler;\n\n    public SimplePerformanceTest()\n    {\n        ringBuffer = RingBuffer.createSingleProducer(EventHolder.FACTORY, Constants.SIZE, new YieldingWaitStrategy());\n        eventHolderHandler = new EventHolderHandler(new SimpleEventHandler());\n    }\n\n    public void run()\n    {\n        try\n        {\n            doRun();\n        }\n        catch (InterruptedException e)\n        {\n            e.printStackTrace();\n        }\n    }\n\n    private void doRun() throws InterruptedException\n    {\n        BatchEventProcessor<EventHolder> batchEventProcessor =\n                new BatchEventProcessorBuilder().build(\n                        ringBuffer,\n                        ringBuffer.newBarrier(),\n                        eventHolderHandler);\n        ringBuffer.addGatingSequences(batchEventProcessor.getSequence());\n\n        Thread t = new Thread(batchEventProcessor);\n        t.start();\n\n        long iterations = Constants.ITERATIONS;\n        for (long l = 0; l < iterations; l++)\n        {\n            SimpleEvent e = new SimpleEvent(l, l, l, l);\n            ringBuffer.publishEvent(TRANSLATOR, e);\n        }\n\n        while (batchEventProcessor.getSequence().get() != iterations - 1)\n        {\n            LockSupport.parkNanos(1);\n        }\n\n        batchEventProcessor.halt();\n        t.join();\n    }\n\n    private static final EventTranslatorOneArg<EventHolder, SimpleEvent> TRANSLATOR =\n            (holder, arg1, event) -> holder.event = event;\n\n    public static void main(final String[] args)\n    {\n        new SimplePerformanceTest().run();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/offheap/OneToOneOffHeapThroughputTest.java",
    "content": "package com.lmax.disruptor.offheap;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.DataProvider;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.Sequencer;\nimport com.lmax.disruptor.SingleProducerSequencer;\nimport com.lmax.disruptor.WaitStrategy;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport com.lmax.disruptor.util.PaddedLong;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.Random;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.locks.LockSupport;\n\npublic class OneToOneOffHeapThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int BLOCK_SIZE = 256;\n    private static final int BUFFER_SIZE = 1024 * 1024;\n    private static final long ITERATIONS = 1000 * 1000 * 10L;\n\n    private final Executor executor = Executors.newFixedThreadPool(1, DaemonThreadFactory.INSTANCE);\n    private final WaitStrategy waitStrategy = new YieldingWaitStrategy();\n    private final OffHeapRingBuffer buffer =\n        new OffHeapRingBuffer(new SingleProducerSequencer(BUFFER_SIZE, waitStrategy), BLOCK_SIZE);\n    private final ByteBufferHandler handler = new ByteBufferHandler();\n    private final BatchEventProcessor<ByteBuffer> processor =\n            new BatchEventProcessorBuilder().build(buffer, buffer.newBarrier(), handler);\n\n    {\n        buffer.addGatingSequences(processor.getSequence());\n    }\n\n    private final Random r = new Random(1);\n    private final byte[] data = new byte[BLOCK_SIZE];\n\n    public OneToOneOffHeapThroughputTest()\n    {\n        r.nextBytes(data);\n    }\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 2;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws Exception\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        byte[] data = this.data;\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        long expectedCount = processor.getSequence().get() + ITERATIONS;\n        handler.reset(latch, ITERATIONS);\n        executor.execute(processor);\n        long start = System.currentTimeMillis();\n\n        final OffHeapRingBuffer rb = buffer;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            rb.put(data);\n        }\n\n        latch.await();\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n        perfTestContext.setBatchData(handler.getBatchesProcessed(), ITERATIONS);\n        waitForEventProcessorSequence(expectedCount);\n        processor.halt();\n\n        return perfTestContext;\n    }\n\n    private void waitForEventProcessorSequence(final long expectedCount)\n    {\n        while (processor.getSequence().get() < expectedCount)\n        {\n            LockSupport.parkNanos(1);\n        }\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new OneToOneOffHeapThroughputTest().testImplementations();\n    }\n\n    public static class ByteBufferHandler implements EventHandler<ByteBuffer>\n    {\n        private final PaddedLong total = new PaddedLong();\n        private final PaddedLong batchesProcessed = new PaddedLong();\n        private long expectedCount;\n        private CountDownLatch latch;\n\n        @Override\n        public void onEvent(final ByteBuffer event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            final int start = event.position();\n            for (int i = start, size = start + BLOCK_SIZE; i < size; i += 8)\n            {\n                total.set(total.get() + event.getLong(i));\n            }\n\n            if (--expectedCount == 0)\n            {\n                latch.countDown();\n            }\n        }\n\n        public long getTotal()\n        {\n            return total.get();\n        }\n\n        public long getBatchesProcessed()\n        {\n            return batchesProcessed.get();\n        }\n\n        public void reset(final CountDownLatch latch, final long expectedCount)\n        {\n            this.latch = latch;\n            this.expectedCount = expectedCount;\n            this.total.set(0);\n            this.batchesProcessed.set(0);\n        }\n\n        @Override\n        public void onBatchStart(final long batchSize, final long queueDepth)\n        {\n            batchesProcessed.increment();\n        }\n    }\n\n    public static class OffHeapRingBuffer implements DataProvider<ByteBuffer>\n    {\n        private final Sequencer sequencer;\n        private final int entrySize;\n        private final ByteBuffer buffer;\n        private final int mask;\n\n        private final ThreadLocal<ByteBuffer> perThreadBuffer = new ThreadLocal<>()\n        {\n            @Override\n            protected ByteBuffer initialValue()\n            {\n                return buffer.duplicate().order(ByteOrder.nativeOrder());\n            }\n        };\n\n        public OffHeapRingBuffer(final Sequencer sequencer, final int entrySize)\n        {\n            this.sequencer = sequencer;\n            this.entrySize = entrySize;\n            this.mask = sequencer.getBufferSize() - 1;\n            buffer = ByteBuffer.allocateDirect(sequencer.getBufferSize() * entrySize).order(ByteOrder.nativeOrder());\n        }\n\n        public void addGatingSequences(final Sequence sequence)\n        {\n            sequencer.addGatingSequences(sequence);\n        }\n\n        public SequenceBarrier newBarrier()\n        {\n            return sequencer.newBarrier();\n        }\n\n        @Override\n        public ByteBuffer get(final long sequence)\n        {\n            int index = index(sequence);\n            int position = index * entrySize;\n            int limit = position + entrySize;\n\n            ByteBuffer byteBuffer = perThreadBuffer.get();\n            byteBuffer.position(position).limit(limit);\n\n            return byteBuffer;\n        }\n\n        public void put(final byte[] data)\n        {\n            long next = sequencer.next();\n            try\n            {\n                get(next).put(data);\n            }\n            finally\n            {\n                sequencer.publish(next);\n            }\n        }\n\n        private int index(final long next)\n        {\n            return (int) (next & mask);\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/offheap/OneToOneOnHeapThroughputTest.java",
    "content": "package com.lmax.disruptor.offheap;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.WaitStrategy;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport com.lmax.disruptor.util.PaddedLong;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.Random;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.locks.LockSupport;\n\npublic class OneToOneOnHeapThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int BLOCK_SIZE = 256;\n    private static final int BUFFER_SIZE = 1024 * 1024;\n    private static final long ITERATIONS = 1000 * 1000 * 10L;\n\n    private static final boolean SLICED_BUFFER = Boolean.getBoolean(\"sliced\");\n    private final Executor executor = Executors.newFixedThreadPool(1, DaemonThreadFactory.INSTANCE);\n    private final WaitStrategy waitStrategy = new YieldingWaitStrategy();\n    private final RingBuffer<ByteBuffer> buffer =\n        RingBuffer.createSingleProducer(\n            SLICED_BUFFER ? SlicedBufferFactory.direct(BLOCK_SIZE, BUFFER_SIZE) : BufferFactory.direct(BLOCK_SIZE),\n            BUFFER_SIZE, waitStrategy);\n        private final ByteBufferHandler handler = new ByteBufferHandler();\n    private final BatchEventProcessor<ByteBuffer> processor =\n            new BatchEventProcessorBuilder().build(buffer, buffer.newBarrier(), handler);\n\n    {\n        buffer.addGatingSequences(processor.getSequence());\n    }\n\n    private final Random r = new Random(1);\n    private final byte[] data = new byte[BLOCK_SIZE];\n\n    public OneToOneOnHeapThroughputTest()\n    {\n        r.nextBytes(data);\n    }\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 2;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws Exception\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        byte[] data = this.data;\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        long expectedCount = processor.getSequence().get() + ITERATIONS;\n        handler.reset(latch, ITERATIONS);\n        executor.execute(processor);\n        long start = System.currentTimeMillis();\n\n        final RingBuffer<ByteBuffer> rb = buffer;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long next = rb.next();\n            ByteBuffer event = rb.get(next);\n            event.clear();\n            event.put(data);\n            event.flip();\n            rb.publish(next);\n        }\n\n        latch.await();\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n        perfTestContext.setBatchData(handler.getBatchesProcessed(), ITERATIONS);\n        waitForEventProcessorSequence(expectedCount);\n        processor.halt();\n\n        return perfTestContext;\n    }\n\n    private void waitForEventProcessorSequence(final long expectedCount)\n    {\n        while (processor.getSequence().get() < expectedCount)\n        {\n            LockSupport.parkNanos(1);\n        }\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new OneToOneOnHeapThroughputTest().testImplementations();\n    }\n\n    public static class ByteBufferHandler implements EventHandler<ByteBuffer>\n    {\n        private final PaddedLong total = new PaddedLong();\n        private final PaddedLong batchesProcessed = new PaddedLong();\n        private long expectedCount;\n        private CountDownLatch latch;\n\n        @Override\n        public void onEvent(final ByteBuffer event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            for (int i = 0; i < BLOCK_SIZE; i += 8)\n            {\n                total.set(total.get() + event.getLong(i));\n            }\n\n            if (--expectedCount == 0)\n            {\n                latch.countDown();\n            }\n        }\n\n        public long getTotal()\n        {\n            return total.get();\n        }\n\n        public long getBatchesProcessed()\n        {\n            return batchesProcessed.get();\n        }\n\n        public void reset(final CountDownLatch latch, final long expectedCount)\n        {\n            this.latch = latch;\n            this.expectedCount = expectedCount;\n            this.total.set(0);\n            this.batchesProcessed.set(0);\n        }\n\n        @Override\n        public void onBatchStart(final long batchSize, final long queueDepth)\n        {\n            batchesProcessed.increment();\n        }\n    }\n\n    private static final class BufferFactory implements EventFactory<ByteBuffer>\n    {\n        private final boolean isDirect;\n        private final int size;\n\n        private BufferFactory(final boolean isDirect, final int size)\n        {\n            this.isDirect = isDirect;\n            this.size = size;\n        }\n\n        @Override\n        public ByteBuffer newInstance()\n        {\n            if (isDirect)\n            {\n                return ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder());\n            }\n            else\n            {\n                return ByteBuffer.allocate(size).order(ByteOrder.nativeOrder());\n            }\n        }\n\n        public static BufferFactory direct(final int size)\n        {\n            return new BufferFactory(true, size);\n        }\n\n        @SuppressWarnings(\"unused\")\n        public static BufferFactory heap(final int size)\n        {\n            return new BufferFactory(false, size);\n        }\n    }\n\n    private static final class SlicedBufferFactory implements EventFactory<ByteBuffer>\n    {\n        private final boolean isDirect;\n        private final int size;\n        private final int total;\n        private ByteBuffer buffer;\n\n        private SlicedBufferFactory(final boolean isDirect, final int size, final int total)\n        {\n            this.isDirect = isDirect;\n            this.size = size;\n            this.total = total;\n            this.buffer =\n                (isDirect ? ByteBuffer.allocateDirect(size * total) : ByteBuffer.allocate(size * total))\n                    .order(ByteOrder.nativeOrder());\n            this.buffer.limit(0);\n        }\n\n        @Override\n        public ByteBuffer newInstance()\n        {\n            if (this.buffer.limit() == this.buffer.capacity())\n            {\n                this.buffer =\n                    (isDirect ? ByteBuffer.allocateDirect(size * total) : ByteBuffer.allocate(size * total))\n                        .order(ByteOrder.nativeOrder());\n                this.buffer.limit(0);\n            }\n            final int limit = this.buffer.limit();\n            this.buffer.limit(limit + size);\n            this.buffer.position(limit);\n            final ByteBuffer slice = this.buffer.slice().order(ByteOrder.nativeOrder());\n            return slice;\n        }\n\n        public static SlicedBufferFactory direct(final int size, final int total)\n        {\n            return new SlicedBufferFactory(true, size, total);\n        }\n\n        @SuppressWarnings(\"unused\")\n        public static SlicedBufferFactory heap(final int size, final int total)\n        {\n            return new SlicedBufferFactory(false, size, total);\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/queue/OneToOneQueueBatchedThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.queue;\n\nimport com.lmax.disruptor.AbstractPerfTestQueue;\nimport com.lmax.disruptor.support.ValueAdditionBatchQueueProcessor;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport static com.lmax.disruptor.support.PerfTestUtil.failIf;\n\n/**\n * <pre>\n * UniCast a series of items between 1 publisher and 1 event processor.\n *\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *\n * Queue Based:\n * ============\n *\n *        put      take\n * +----+    +====+    +-----+\n * | P1 |--->| Q1 |<---| EP1 |\n * +----+    +====+    +-----+\n *\n * P1  - Publisher 1\n * Q1  - Queue 1\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class OneToOneQueueBatchedThroughputTest extends AbstractPerfTestQueue\n{\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 10L;\n    private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);\n    private final long expectedResult = ITERATIONS * 3L;\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final BlockingQueue<Long> blockingQueue = new LinkedBlockingQueue<>(BUFFER_SIZE);\n    private final ValueAdditionBatchQueueProcessor queueProcessor =\n        new ValueAdditionBatchQueueProcessor(blockingQueue, ITERATIONS);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 2;\n    }\n\n    @Override\n    protected long runQueuePass() throws InterruptedException\n    {\n        final CountDownLatch latch = new CountDownLatch(1);\n        queueProcessor.reset(latch);\n        Future<?> future = executor.submit(queueProcessor);\n        long start = System.currentTimeMillis();\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            blockingQueue.put(3L);\n        }\n\n        latch.await();\n        long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);\n        queueProcessor.halt();\n        future.cancel(true);\n\n        failIf(expectedResult, 0);\n\n        return opsPerSecond;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        OneToOneQueueBatchedThroughputTest test = new OneToOneQueueBatchedThroughputTest();\n        test.testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/queue/OneToOneQueueThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.queue;\n\nimport com.lmax.disruptor.AbstractPerfTestQueue;\nimport com.lmax.disruptor.support.ValueAdditionQueueProcessor;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport static com.lmax.disruptor.support.PerfTestUtil.failIf;\n\n/**\n * <pre>\n * UniCast a series of items between 1 publisher and 1 event processor.\n *\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *\n * Queue Based:\n * ============\n *\n *        put      take\n * +----+    +====+    +-----+\n * | P1 |--->| Q1 |<---| EP1 |\n * +----+    +====+    +-----+\n *\n * P1  - Publisher 1\n * Q1  - Queue 1\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class OneToOneQueueThroughputTest extends AbstractPerfTestQueue\n{\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 10L;\n    private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);\n    private final long expectedResult = ITERATIONS * 3L;\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final BlockingQueue<Long> blockingQueue = new LinkedBlockingQueue<>(BUFFER_SIZE);\n    private final ValueAdditionQueueProcessor queueProcessor =\n        new ValueAdditionQueueProcessor(blockingQueue, ITERATIONS - 1);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 2;\n    }\n\n    @Override\n    protected long runQueuePass() throws InterruptedException\n    {\n        final CountDownLatch latch = new CountDownLatch(1);\n        queueProcessor.reset(latch);\n        Future<?> future = executor.submit(queueProcessor);\n        long start = System.currentTimeMillis();\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            blockingQueue.put(3L);\n        }\n\n        latch.await();\n        long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);\n        queueProcessor.halt();\n        future.cancel(true);\n\n        failIf(expectedResult, 0);\n\n        return opsPerSecond;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        OneToOneQueueThroughputTest test = new OneToOneQueueThroughputTest();\n        test.testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/queue/OneToThreeDiamondQueueThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.queue;\n\nimport com.lmax.disruptor.AbstractPerfTestQueue;\nimport com.lmax.disruptor.support.FizzBuzzQueueProcessor;\nimport com.lmax.disruptor.support.FizzBuzzStep;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport static com.lmax.disruptor.support.PerfTestUtil.failIf;\n\n/**\n * <pre>\n * Produce an event replicated to two event processors and fold back to a single third event processor.\n *\n *           +-----+\n *    +----->| EP1 |------+\n *    |      +-----+      |\n *    |                   v\n * +----+              +-----+\n * | P1 |              | EP3 |\n * +----+              +-----+\n *    |                   ^\n *    |      +-----+      |\n *    +----->| EP2 |------+\n *           +-----+\n *\n *\n * Queue Based:\n * ============\n *                 take       put\n *     put   +====+    +-----+    +====+  take\n *    +----->| Q1 |<---| EP1 |--->| Q3 |<------+\n *    |      +====+    +-----+    +====+       |\n *    |                                        |\n * +----+    +====+    +-----+    +====+    +-----+\n * | P1 |--->| Q2 |<---| EP2 |--->| Q4 |<---| EP3 |\n * +----+    +====+    +-----+    +====+    +-----+\n *\n * P1  - Publisher 1\n * Q1  - Queue 1\n * Q2  - Queue 2\n * Q3  - Queue 3\n * Q4  - Queue 4\n * EP1 - EventProcessor 1\n * EP2 - EventProcessor 2\n * EP3 - EventProcessor 3\n *\n *\n * Disruptor:\n * ==========\n *                    track to prevent wrap\n *              +-------------------------------+\n *              |                               |\n *              |                               v\n * +----+    +====+               +=====+    +-----+\n * | P1 |--->| RB |<--------------| SB2 |<---| EP3 |\n * +----+    +====+               +=====+    +-----+\n *      claim   ^  get               |   waitFor\n *              |                    |\n *           +=====+    +-----+      |\n *           | SB1 |<---| EP1 |<-----+\n *           +=====+    +-----+      |\n *              ^                    |\n *              |       +-----+      |\n *              +-------| EP2 |<-----+\n *             waitFor  +-----+\n *\n * P1  - Publisher 1\n * RB  - RingBuffer\n * SB1 - SequenceBarrier 1\n * EP1 - EventProcessor 1\n * EP2 - EventProcessor 2\n * SB2 - SequenceBarrier 2\n * EP3 - EventProcessor 3\n *\n * </pre>\n */\npublic final class OneToThreeDiamondQueueThroughputTest extends AbstractPerfTestQueue\n{\n    private static final int NUM_EVENT_PROCESSORS = 3;\n    private static final int BUFFER_SIZE = 1024 * 8;\n    private static final long ITERATIONS = 1000L * 1000L * 100L;\n    private final ExecutorService executor = Executors.newFixedThreadPool(NUM_EVENT_PROCESSORS, DaemonThreadFactory.INSTANCE);\n\n    private final long expectedResult;\n\n    {\n        long temp = 0L;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            boolean fizz = 0 == (i % 3L);\n            boolean buzz = 0 == (i % 5L);\n\n            if (fizz && buzz)\n            {\n                ++temp;\n            }\n        }\n\n        expectedResult = temp;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final BlockingQueue<Long> fizzInputQueue = new LinkedBlockingQueue<>(BUFFER_SIZE);\n    private final BlockingQueue<Long> buzzInputQueue = new LinkedBlockingQueue<>(BUFFER_SIZE);\n    private final BlockingQueue<Boolean> fizzOutputQueue = new LinkedBlockingQueue<>(BUFFER_SIZE);\n    private final BlockingQueue<Boolean> buzzOutputQueue = new LinkedBlockingQueue<>(BUFFER_SIZE);\n\n    private final FizzBuzzQueueProcessor fizzQueueProcessor =\n        new FizzBuzzQueueProcessor(FizzBuzzStep.FIZZ, fizzInputQueue, buzzInputQueue, fizzOutputQueue, buzzOutputQueue, ITERATIONS - 1);\n\n    private final FizzBuzzQueueProcessor buzzQueueProcessor =\n        new FizzBuzzQueueProcessor(FizzBuzzStep.BUZZ, fizzInputQueue, buzzInputQueue, fizzOutputQueue, buzzOutputQueue, ITERATIONS - 1);\n\n    private final FizzBuzzQueueProcessor fizzBuzzQueueProcessor =\n        new FizzBuzzQueueProcessor(FizzBuzzStep.FIZZ_BUZZ, fizzInputQueue, buzzInputQueue, fizzOutputQueue, buzzOutputQueue, ITERATIONS - 1);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 4;\n    }\n\n    @Override\n    protected long runQueuePass() throws Exception\n    {\n        final CountDownLatch latch = new CountDownLatch(1);\n        fizzBuzzQueueProcessor.reset(latch);\n\n        Future<?>[] futures = new Future[NUM_EVENT_PROCESSORS];\n        futures[0] = executor.submit(fizzQueueProcessor);\n        futures[1] = executor.submit(buzzQueueProcessor);\n        futures[2] = executor.submit(fizzBuzzQueueProcessor);\n\n        long start = System.currentTimeMillis();\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            Long value = Long.valueOf(i);\n            fizzInputQueue.put(value);\n            buzzInputQueue.put(value);\n        }\n\n        latch.await();\n        long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);\n\n        fizzQueueProcessor.halt();\n        buzzQueueProcessor.halt();\n        fizzBuzzQueueProcessor.halt();\n\n        for (Future<?> future : futures)\n        {\n            future.cancel(true);\n        }\n\n        failIf(expectedResult, 0);\n\n        return opsPerSecond;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new OneToThreeDiamondQueueThroughputTest().testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/queue/OneToThreePipelineQueueThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.queue;\n\nimport com.lmax.disruptor.AbstractPerfTestQueue;\nimport com.lmax.disruptor.support.FunctionQueueProcessor;\nimport com.lmax.disruptor.support.FunctionStep;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport static com.lmax.disruptor.support.PerfTestUtil.failIf;\n\n/**\n * <pre>\n *\n * Pipeline a series of stages from a publisher to ultimate event processor.\n * Each event processor depends on the output of the event processor.\n *\n * +----+    +-----+    +-----+    +-----+\n * | P1 |--->| EP1 |--->| EP2 |--->| EP3 |\n * +----+    +-----+    +-----+    +-----+\n *\n *\n * Queue Based:\n * ============\n *\n *        put      take        put      take        put      take\n * +----+    +====+    +-----+    +====+    +-----+    +====+    +-----+\n * | P1 |--->| Q1 |<---| EP1 |--->| Q2 |<---| EP2 |--->| Q3 |<---| EP3 |\n * +----+    +====+    +-----+    +====+    +-----+    +====+    +-----+\n *\n * P1  - Publisher 1\n * Q1  - Queue 1\n * EP1 - EventProcessor 1\n * Q2  - Queue 2\n * EP2 - EventProcessor 2\n * Q3  - Queue 3\n * EP3 - EventProcessor 3\n *\n * </pre>\n */\npublic final class OneToThreePipelineQueueThroughputTest extends AbstractPerfTestQueue\n{\n    private static final int NUM_EVENT_PROCESSORS = 3;\n    private static final int BUFFER_SIZE = 1024 * 8;\n    private static final long ITERATIONS = 1000L * 1000L * 10L;\n    private final ExecutorService executor = Executors.newFixedThreadPool(NUM_EVENT_PROCESSORS, DaemonThreadFactory.INSTANCE);\n\n    private static final long OPERAND_TWO_INITIAL_VALUE = 777L;\n    private final long expectedResult;\n\n    {\n        long temp = 0L;\n        long operandTwo = OPERAND_TWO_INITIAL_VALUE;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long stepOneResult = i + operandTwo--;\n            long stepTwoResult = stepOneResult + 3;\n\n            if ((stepTwoResult & 4L) == 4L)\n            {\n                ++temp;\n            }\n        }\n\n        expectedResult = temp;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final BlockingQueue<long[]> stepOneQueue = new LinkedBlockingQueue<>(BUFFER_SIZE);\n    private final BlockingQueue<Long> stepTwoQueue = new LinkedBlockingQueue<>(BUFFER_SIZE);\n    private final BlockingQueue<Long> stepThreeQueue = new LinkedBlockingQueue<>(BUFFER_SIZE);\n\n    private final FunctionQueueProcessor stepOneQueueProcessor =\n        new FunctionQueueProcessor(FunctionStep.ONE, stepOneQueue, stepTwoQueue, stepThreeQueue, ITERATIONS - 1);\n    private final FunctionQueueProcessor stepTwoQueueProcessor =\n        new FunctionQueueProcessor(FunctionStep.TWO, stepOneQueue, stepTwoQueue, stepThreeQueue, ITERATIONS - 1);\n    private final FunctionQueueProcessor stepThreeQueueProcessor =\n        new FunctionQueueProcessor(FunctionStep.THREE, stepOneQueue, stepTwoQueue, stepThreeQueue, ITERATIONS - 1);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 4;\n    }\n\n    @Override\n    protected long runQueuePass() throws Exception\n    {\n        CountDownLatch latch = new CountDownLatch(1);\n        stepThreeQueueProcessor.reset(latch);\n\n        Future<?>[] futures = new Future[NUM_EVENT_PROCESSORS];\n        futures[0] = executor.submit(stepOneQueueProcessor);\n        futures[1] = executor.submit(stepTwoQueueProcessor);\n        futures[2] = executor.submit(stepThreeQueueProcessor);\n\n        long start = System.currentTimeMillis();\n\n        long operandTwo = OPERAND_TWO_INITIAL_VALUE;\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long[] values = new long[2];\n            values[0] = i;\n            values[1] = operandTwo--;\n            stepOneQueue.put(values);\n        }\n\n        latch.await();\n        long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);\n\n        stepOneQueueProcessor.halt();\n        stepTwoQueueProcessor.halt();\n        stepThreeQueueProcessor.halt();\n\n        for (Future<?> future : futures)\n        {\n            future.cancel(true);\n        }\n\n        failIf(expectedResult, 0);\n\n        return opsPerSecond;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new OneToThreePipelineQueueThroughputTest().testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/queue/OneToThreeQueueThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.queue;\n\nimport com.lmax.disruptor.AbstractPerfTestQueue;\nimport com.lmax.disruptor.support.Operation;\nimport com.lmax.disruptor.support.ValueMutationQueueProcessor;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport static com.lmax.disruptor.support.PerfTestUtil.failIf;\n\n/**\n * <pre>\n *\n * MultiCast a series of items between 1 publisher and 3 event processors.\n *\n *           +-----+\n *    +----->| EP1 |\n *    |      +-----+\n *    |\n * +----+    +-----+\n * | P1 |--->| EP2 |\n * +----+    +-----+\n *    |\n *    |      +-----+\n *    +----->| EP3 |\n *           +-----+\n *\n *\n * Queue Based:\n * ============\n *                 take\n *   put     +====+    +-----+\n *    +----->| Q1 |<---| EP1 |\n *    |      +====+    +-----+\n *    |\n * +----+    +====+    +-----+\n * | P1 |--->| Q2 |<---| EP2 |\n * +----+    +====+    +-----+\n *    |\n *    |      +====+    +-----+\n *    +----->| Q3 |<---| EP3 |\n *           +====+    +-----+\n *\n * P1  - Publisher 1\n * Q1  - Queue 1\n * Q2  - Queue 2\n * Q3  - Queue 3\n * EP1 - EventProcessor 1\n * EP2 - EventProcessor 2\n * EP3 - EventProcessor 3\n *\n * </pre>\n */\npublic final class OneToThreeQueueThroughputTest extends AbstractPerfTestQueue\n{\n    private static final int NUM_EVENT_PROCESSORS = 3;\n    private static final int BUFFER_SIZE = 1024 * 8;\n    private static final long ITERATIONS = 1000L * 1000L * 1L;\n    private final ExecutorService executor = Executors.newFixedThreadPool(NUM_EVENT_PROCESSORS, DaemonThreadFactory.INSTANCE);\n\n    private final long[] results = new long[NUM_EVENT_PROCESSORS];\n\n    {\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            results[0] = Operation.ADDITION.op(results[0], i);\n            results[1] = Operation.SUBTRACTION.op(results[1], i);\n            results[2] = Operation.AND.op(results[2], i);\n        }\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @SuppressWarnings(\"unchecked\")\n    private final BlockingQueue<Long>[] blockingQueues = new BlockingQueue[NUM_EVENT_PROCESSORS];\n\n    {\n        blockingQueues[0] = new LinkedBlockingQueue<>(BUFFER_SIZE);\n        blockingQueues[1] = new LinkedBlockingQueue<>(BUFFER_SIZE);\n        blockingQueues[2] = new LinkedBlockingQueue<>(BUFFER_SIZE);\n    }\n\n    private final ValueMutationQueueProcessor[] queueProcessors = new ValueMutationQueueProcessor[NUM_EVENT_PROCESSORS];\n\n    {\n        queueProcessors[0] = new ValueMutationQueueProcessor(blockingQueues[0], Operation.ADDITION, ITERATIONS - 1);\n        queueProcessors[1] = new ValueMutationQueueProcessor(blockingQueues[1], Operation.SUBTRACTION, ITERATIONS - 1);\n        queueProcessors[2] = new ValueMutationQueueProcessor(blockingQueues[2], Operation.AND, ITERATIONS - 1);\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 4;\n    }\n\n    @Override\n    protected long runQueuePass() throws InterruptedException\n    {\n        CountDownLatch latch = new CountDownLatch(NUM_EVENT_PROCESSORS);\n        Future<?>[] futures = new Future[NUM_EVENT_PROCESSORS];\n        for (int i = 0; i < NUM_EVENT_PROCESSORS; i++)\n        {\n            queueProcessors[i].reset(latch);\n            futures[i] = executor.submit(queueProcessors[i]);\n        }\n\n        long start = System.currentTimeMillis();\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            final Long value = Long.valueOf(i);\n            for (BlockingQueue<Long> queue : blockingQueues)\n            {\n                queue.put(value);\n            }\n        }\n\n        latch.await();\n        long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);\n        for (int i = 0; i < NUM_EVENT_PROCESSORS; i++)\n        {\n            queueProcessors[i].halt();\n            futures[i].cancel(true);\n            failIf(queueProcessors[i].getValue(), -1);\n        }\n\n        return opsPerSecond;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new OneToThreeQueueThroughputTest().testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/queue/PingPongQueueLatencyTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.queue;\n\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport org.HdrHistogram.Histogram;\n\nimport java.io.PrintStream;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\n/**\n * <pre>\n *\n * Ping pongs between 2 event handlers and measures the latency of\n * a round trip.\n *\n * Queue Based:\n * ============\n *               +---take---+\n *               |          |\n *               |          V\n *            +====+      +====+\n *    +------>| Q1 |      | P2 |-------+\n *    |       +====+      +====+       |\n *   put                              put\n *    |       +====+      +====+       |\n *    +-------| P1 |      | Q2 |<------+\n *            +====+      +====+\n *               ^          |\n *               |          |\n *               +---take---+\n *\n * P1 - QueuePinger\n * P2 - QueuePonger\n * Q1 - PingQueue\n * Q2 - PongQueue\n *\n * </pre>\n *\n * <p>Note: <b>This test is only useful on a system using an invariant TSC in user space from the System.nanoTime() call.</b>\n */\npublic final class PingPongQueueLatencyTest\n{\n    private static final int BUFFER_SIZE = 1024;\n    private static final long ITERATIONS = 100L * 1000L * 30L;\n    private static final long PAUSE_NANOS = 1000L;\n    private final ExecutorService executor = Executors.newCachedThreadPool(DaemonThreadFactory.INSTANCE);\n\n    private final Histogram histogram = new Histogram(10000000000L, 4);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final BlockingQueue<Long> pingQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);\n    private final BlockingQueue<Long> pongQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);\n    private final QueuePinger qPinger = new QueuePinger(pingQueue, pongQueue, ITERATIONS, PAUSE_NANOS);\n    private final QueuePonger qPonger = new QueuePonger(pingQueue, pongQueue);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    public void testImplementation() throws Exception\n    {\n        final int runs = 3;\n\n        for (int i = 0; i < runs; i++)\n        {\n            System.gc();\n            histogram.reset();\n\n            runQueuePass();\n\n            System.out.format(\"%s run %d BlockingQueue %s\\n\", getClass().getSimpleName(), Long.valueOf(i), histogram);\n            dumpHistogram(histogram, System.out);\n        }\n    }\n\n    private static void dumpHistogram(final Histogram histogram, final PrintStream out)\n    {\n        histogram.outputPercentileDistribution(out, 1, 1000.0);\n    }\n\n    private void runQueuePass() throws Exception\n    {\n        final CountDownLatch latch = new CountDownLatch(1);\n        final CyclicBarrier barrier = new CyclicBarrier(3);\n        qPinger.reset(barrier, latch, histogram);\n        qPonger.reset(barrier);\n\n        final Future<?> pingFuture = executor.submit(qPinger);\n        final Future<?> pongFuture = executor.submit(qPonger);\n\n        barrier.await();\n        latch.await();\n\n        pingFuture.cancel(true);\n        pongFuture.cancel(true);\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        final PingPongQueueLatencyTest test = new PingPongQueueLatencyTest();\n        test.testImplementation();\n    }\n\n    private static class QueuePinger implements Runnable\n    {\n        private final BlockingQueue<Long> pingQueue;\n        private final BlockingQueue<Long> pongQueue;\n        private final long pauseTimeNs;\n\n        private Histogram histogram;\n        private CyclicBarrier barrier;\n        private CountDownLatch latch;\n        private long counter;\n        private final long maxEvents;\n\n        QueuePinger(\n            final BlockingQueue<Long> pingQueue, final BlockingQueue<Long> pongQueue, final long maxEvents,\n            final long pauseTimeNs)\n        {\n            this.pingQueue = pingQueue;\n            this.pongQueue = pongQueue;\n            this.maxEvents = maxEvents;\n            this.pauseTimeNs = pauseTimeNs;\n        }\n\n        @Override\n        public void run()\n        {\n            try\n            {\n                barrier.await();\n\n                Thread.sleep(1000);\n\n                long counter = 0;\n\n                while (counter < maxEvents)\n                {\n                    final long t0 = System.nanoTime();\n                    pingQueue.put(1L);\n                    counter += pongQueue.take();\n                    final long t1 = System.nanoTime();\n\n                    histogram.recordValueWithExpectedInterval(t1 - t0, pauseTimeNs);\n\n                    while (pauseTimeNs > (System.nanoTime() - t1))\n                    {\n                        Thread.yield();\n                    }\n                }\n\n                latch.countDown();\n            }\n            catch (final Exception e)\n            {\n                e.printStackTrace();\n                return;\n            }\n        }\n\n        public void reset(final CyclicBarrier barrier, final CountDownLatch latch, final Histogram histogram)\n        {\n            this.histogram = histogram;\n            this.barrier = barrier;\n            this.latch = latch;\n\n            counter = 0;\n        }\n    }\n\n    private static class QueuePonger implements Runnable\n    {\n        private final BlockingQueue<Long> pingQueue;\n        private final BlockingQueue<Long> pongQueue;\n        private CyclicBarrier barrier;\n\n        QueuePonger(final BlockingQueue<Long> pingQueue, final BlockingQueue<Long> pongQueue)\n        {\n            this.pingQueue = pingQueue;\n            this.pongQueue = pongQueue;\n        }\n\n        @Override\n        public void run()\n        {\n            final Thread thread = Thread.currentThread();\n            try\n            {\n                barrier.await();\n\n                while (!thread.isInterrupted())\n                {\n                    final Long value = pingQueue.take();\n                    pongQueue.put(value);\n                }\n            }\n            catch (final InterruptedException e)\n            {\n                // do-nothing.\n            }\n            catch (final Exception e)\n            {\n                e.printStackTrace();\n            }\n        }\n\n        public void reset(final CyclicBarrier barrier)\n        {\n            this.barrier = barrier;\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/queue/ThreeToOneQueueBatchThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.queue;\n\nimport com.lmax.disruptor.AbstractPerfTestQueue;\nimport com.lmax.disruptor.support.ValueAdditionQueueBatchProcessor;\nimport com.lmax.disruptor.support.ValueQueuePublisher;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\n/**\n * <pre>\n *\n * Sequence a series of events from multiple publishers going to one event processor.\n *\n * +----+\n * | P1 |------+\n * +----+      |\n *             v\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *             ^\n * +----+      |\n * | P3 |------+\n * +----+\n *\n *\n * Queue Based:\n * ============\n *\n * +----+  put\n * | P1 |------+\n * +----+      |\n *             v   take\n * +----+    +====+    +-----+\n * | P2 |--->| Q1 |<---| EP1 |\n * +----+    +====+    +-----+\n *             ^\n * +----+      |\n * | P3 |------+\n * +----+\n *\n * P1  - Publisher 1\n * P2  - Publisher 2\n * P3  - Publisher 3\n * Q1  - Queue 1\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class ThreeToOneQueueBatchThroughputTest extends AbstractPerfTestQueue\n{\n    private static final int NUM_PUBLISHERS = 3;\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 20L;\n    private final ExecutorService executor = Executors.newFixedThreadPool(NUM_PUBLISHERS + 1, DaemonThreadFactory.INSTANCE);\n    private final CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM_PUBLISHERS + 1);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final BlockingQueue<Long> blockingQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);\n    private final ValueAdditionQueueBatchProcessor queueProcessor =\n        new ValueAdditionQueueBatchProcessor(blockingQueue, ((ITERATIONS / NUM_PUBLISHERS) * NUM_PUBLISHERS) - 1L);\n    private final ValueQueuePublisher[] valueQueuePublishers = new ValueQueuePublisher[NUM_PUBLISHERS];\n\n    {\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            valueQueuePublishers[i] =\n                new ValueQueuePublisher(cyclicBarrier, blockingQueue, ITERATIONS / NUM_PUBLISHERS);\n        }\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 4;\n    }\n\n    @Override\n    protected long runQueuePass() throws Exception\n    {\n        final CountDownLatch latch = new CountDownLatch(1);\n        queueProcessor.reset(latch);\n\n        Future<?>[] futures = new Future[NUM_PUBLISHERS];\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            futures[i] = executor.submit(valueQueuePublishers[i]);\n        }\n        Future<?> processorFuture = executor.submit(queueProcessor);\n\n        long start = System.currentTimeMillis();\n        cyclicBarrier.await();\n\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            futures[i].get();\n        }\n\n        latch.await();\n\n        long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);\n        queueProcessor.halt();\n        processorFuture.cancel(true);\n\n        return opsPerSecond;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new ThreeToOneQueueBatchThroughputTest().testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/queue/ThreeToOneQueueThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.queue;\n\nimport com.lmax.disruptor.AbstractPerfTestQueue;\nimport com.lmax.disruptor.support.ValueAdditionQueueProcessor;\nimport com.lmax.disruptor.support.ValueQueuePublisher;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\n/**\n * <pre>\n *\n * Sequence a series of events from multiple publishers going to one event processor.\n *\n * +----+\n * | P1 |------+\n * +----+      |\n *             v\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *             ^\n * +----+      |\n * | P3 |------+\n * +----+\n *\n *\n * Queue Based:\n * ============\n *\n * +----+  put\n * | P1 |------+\n * +----+      |\n *             v   take\n * +----+    +====+    +-----+\n * | P2 |--->| Q1 |<---| EP1 |\n * +----+    +====+    +-----+\n *             ^\n * +----+      |\n * | P3 |------+\n * +----+\n *\n * P1  - Publisher 1\n * P2  - Publisher 2\n * P3  - Publisher 3\n * Q1  - Queue 1\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class ThreeToOneQueueThroughputTest extends AbstractPerfTestQueue\n{\n    private static final int NUM_PUBLISHERS = 3;\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 20L;\n    private final ExecutorService executor = Executors.newFixedThreadPool(NUM_PUBLISHERS + 1, DaemonThreadFactory.INSTANCE);\n    private final CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM_PUBLISHERS + 1);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final BlockingQueue<Long> blockingQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);\n    private final ValueAdditionQueueProcessor queueProcessor =\n        new ValueAdditionQueueProcessor(blockingQueue, ((ITERATIONS / NUM_PUBLISHERS) * NUM_PUBLISHERS) - 1L);\n    private final ValueQueuePublisher[] valueQueuePublishers = new ValueQueuePublisher[NUM_PUBLISHERS];\n\n    {\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            valueQueuePublishers[i] =\n                new ValueQueuePublisher(cyclicBarrier, blockingQueue, ITERATIONS / NUM_PUBLISHERS);\n        }\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 4;\n    }\n\n    @Override\n    protected long runQueuePass() throws Exception\n    {\n        final CountDownLatch latch = new CountDownLatch(1);\n        queueProcessor.reset(latch);\n\n        Future<?>[] futures = new Future[NUM_PUBLISHERS];\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            futures[i] = executor.submit(valueQueuePublishers[i]);\n        }\n        Future<?> processorFuture = executor.submit(queueProcessor);\n\n        long start = System.currentTimeMillis();\n        cyclicBarrier.await();\n\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            futures[i].get();\n        }\n\n        latch.await();\n\n        long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start);\n        queueProcessor.halt();\n        processorFuture.cancel(true);\n\n        return opsPerSecond;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new ThreeToOneQueueThroughputTest().testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/raw/OneToOneRawBatchThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.raw;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.Sequenced;\nimport com.lmax.disruptor.Sequencer;\nimport com.lmax.disruptor.SingleProducerSequencer;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * <pre>\n * UniCast a series of items between 1 publisher and 1 event processor.\n *\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *\n *\n * Queue Based:\n * ============\n *\n *        put      take\n * +----+    +====+    +-----+\n * | P1 |--->| Q1 |<---| EP1 |\n * +----+    +====+    +-----+\n *\n * P1  - Publisher 1\n * Q1  - Queue 1\n * EP1 - EventProcessor 1\n *\n *\n * Disruptor:\n * ==========\n *              track to prevent wrap\n *              +------------------+\n *              |                  |\n *              |                  v\n * +----+    +====+    +====+   +-----+\n * | P1 |--->| RB |<---| SB |   | EP1 |\n * +----+    +====+    +====+   +-----+\n *      claim      get    ^        |\n *                        |        |\n *                        +--------+\n *                          waitFor\n *\n * P1  - Publisher 1\n * RB  - RingBuffer\n * SB  - SequenceBarrier\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class OneToOneRawBatchThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 200L;\n    private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final Sequencer sequencer = new SingleProducerSequencer(BUFFER_SIZE, new YieldingWaitStrategy());\n    private final MyRunnable myRunnable = new MyRunnable(sequencer);\n\n    {\n        sequencer.addGatingSequences(myRunnable.sequence);\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 2;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws InterruptedException\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        int batchSize = 10;\n        final CountDownLatch latch = new CountDownLatch(1);\n        long expectedCount = myRunnable.sequence.get() + (ITERATIONS * batchSize);\n        myRunnable.reset(latch, expectedCount);\n        executor.submit(myRunnable);\n        long start = System.currentTimeMillis();\n\n        final Sequenced sequencer = this.sequencer;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long next = sequencer.next(batchSize);\n            sequencer.publish((next - (batchSize - 1)), next);\n        }\n\n        latch.await();\n        long end = System.currentTimeMillis();\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L * batchSize) / (end - start));\n        waitForEventProcessorSequence(expectedCount);\n\n        return perfTestContext;\n    }\n\n    private void waitForEventProcessorSequence(final long expectedCount) throws InterruptedException\n    {\n        while (myRunnable.sequence.get() != expectedCount)\n        {\n            Thread.sleep(1);\n        }\n    }\n\n    private static class MyRunnable implements Runnable\n    {\n        private CountDownLatch latch;\n        private long expectedCount;\n        Sequence sequence = new Sequence(-1);\n        private final SequenceBarrier barrier;\n\n        MyRunnable(final Sequencer sequencer)\n        {\n            this.barrier = sequencer.newBarrier();\n        }\n\n        public void reset(final CountDownLatch latch, final long expectedCount)\n        {\n            this.latch = latch;\n            this.expectedCount = expectedCount;\n        }\n\n        @Override\n        public void run()\n        {\n            long expected = expectedCount;\n            long processed = -1;\n\n            try\n            {\n                do\n                {\n                    processed = barrier.waitFor(sequence.get() + 1);\n                    sequence.set(processed);\n                }\n                while (processed < expected);\n\n                latch.countDown();\n                sequence.set(processed);\n            }\n            catch (Exception e)\n            {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        OneToOneRawBatchThroughputTest test = new OneToOneRawBatchThroughputTest();\n        test.testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/raw/OneToOneRawThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.raw;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.Sequenced;\nimport com.lmax.disruptor.Sequencer;\nimport com.lmax.disruptor.SingleProducerSequencer;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * <pre>\n * UniCast a series of items between 1 publisher and 1 event processor.\n *\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *\n *\n * Queue Based:\n * ============\n *\n *        put      take\n * +----+    +====+    +-----+\n * | P1 |--->| Q1 |<---| EP1 |\n * +----+    +====+    +-----+\n *\n * P1  - Publisher 1\n * Q1  - Queue 1\n * EP1 - EventProcessor 1\n *\n *\n * Disruptor:\n * ==========\n *              track to prevent wrap\n *              +------------------+\n *              |                  |\n *              |                  v\n * +----+    +====+    +====+   +-----+\n * | P1 |--->| RB |<---| SB |   | EP1 |\n * +----+    +====+    +====+   +-----+\n *      claim      get    ^        |\n *                        |        |\n *                        +--------+\n *                          waitFor\n *\n * P1  - Publisher 1\n * RB  - RingBuffer\n * SB  - SequenceBarrier\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class OneToOneRawThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 200L;\n    private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final Sequencer sequencer = new SingleProducerSequencer(BUFFER_SIZE, new YieldingWaitStrategy());\n    private final MyRunnable myRunnable = new MyRunnable(sequencer);\n\n    {\n        sequencer.addGatingSequences(myRunnable.sequence);\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 2;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws InterruptedException\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        final CountDownLatch latch = new CountDownLatch(1);\n        long expectedCount = myRunnable.sequence.get() + ITERATIONS;\n        myRunnable.reset(latch, expectedCount);\n        executor.submit(myRunnable);\n        long start = System.currentTimeMillis();\n\n        final Sequenced sequencer = this.sequencer;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long next = sequencer.next();\n            sequencer.publish(next);\n        }\n\n        latch.await();\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n        waitForEventProcessorSequence(expectedCount);\n\n        return perfTestContext;\n    }\n\n    private void waitForEventProcessorSequence(final long expectedCount) throws InterruptedException\n    {\n        while (myRunnable.sequence.get() != expectedCount)\n        {\n            Thread.sleep(1);\n        }\n    }\n\n    private static class MyRunnable implements Runnable\n    {\n        private CountDownLatch latch;\n        private long expectedCount;\n        Sequence sequence = new Sequence(-1);\n        private final SequenceBarrier barrier;\n\n        MyRunnable(final Sequencer sequencer)\n        {\n            this.barrier = sequencer.newBarrier();\n        }\n\n        public void reset(final CountDownLatch latch, final long expectedCount)\n        {\n            this.latch = latch;\n            this.expectedCount = expectedCount;\n        }\n\n        @Override\n        public void run()\n        {\n            long expected = expectedCount;\n            long processed = -1;\n\n            try\n            {\n                do\n                {\n                    processed = barrier.waitFor(sequence.get() + 1);\n                    sequence.set(processed);\n                }\n                while (processed < expected);\n\n                latch.countDown();\n                sequence.setVolatile(processed);\n            }\n            catch (Exception e)\n            {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        OneToOneRawThroughputTest test = new OneToOneRawThroughputTest();\n        test.testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/sequenced/OneToOneSequencedBatchThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.sequenced;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.support.PerfTestUtil;\nimport com.lmax.disruptor.support.ValueAdditionEventHandler;\nimport com.lmax.disruptor.support.ValueEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static com.lmax.disruptor.RingBuffer.createSingleProducer;\nimport static com.lmax.disruptor.support.PerfTestUtil.failIfNot;\n\n/**\n * <pre>\n * UniCast a series of items between 1 publisher and 1 event processor.\n *\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *\n * Disruptor:\n * ==========\n *              track to prevent wrap\n *              +------------------+\n *              |                  |\n *              |                  v\n * +----+    +====+    +====+   +-----+\n * | P1 |--->| RB |<---| SB |   | EP1 |\n * +----+    +====+    +====+   +-----+\n *      claim      get    ^        |\n *                        |        |\n *                        +--------+\n *                          waitFor\n *\n * P1  - Publisher 1\n * RB  - RingBuffer\n * SB  - SequenceBarrier\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class OneToOneSequencedBatchThroughputTest extends AbstractPerfTestDisruptor\n{\n    public static final int BATCH_SIZE = 10;\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 100L;\n    private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);\n    private final long expectedResult = PerfTestUtil.accumulatedAddition(ITERATIONS) * BATCH_SIZE;\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final RingBuffer<ValueEvent> ringBuffer =\n        createSingleProducer(ValueEvent.EVENT_FACTORY, BUFFER_SIZE, new YieldingWaitStrategy());\n    private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n    private final ValueAdditionEventHandler handler = new ValueAdditionEventHandler();\n    private final BatchEventProcessor<ValueEvent> batchEventProcessor =\n            new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, handler);\n\n    {\n        ringBuffer.addGatingSequences(batchEventProcessor.getSequence());\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 2;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws InterruptedException\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        final CountDownLatch latch = new CountDownLatch(1);\n        long expectedCount = batchEventProcessor.getSequence().get() + ITERATIONS * BATCH_SIZE;\n        handler.reset(latch, expectedCount);\n        executor.submit(batchEventProcessor);\n        long start = System.currentTimeMillis();\n\n        final RingBuffer<ValueEvent> rb = ringBuffer;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long hi = rb.next(BATCH_SIZE);\n            long lo = hi - (BATCH_SIZE - 1);\n            for (long l = lo; l <= hi; l++)\n            {\n                rb.get(l).setValue(i);\n            }\n            rb.publish(lo, hi);\n        }\n\n        latch.await();\n        perfTestContext.setDisruptorOps((BATCH_SIZE * ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n        perfTestContext.setBatchData(handler.getBatchesProcessed(), ITERATIONS * BATCH_SIZE);\n        waitForEventProcessorSequence(expectedCount);\n        batchEventProcessor.halt();\n\n        failIfNot(expectedResult, handler.getValue());\n\n        return perfTestContext;\n    }\n\n    private void waitForEventProcessorSequence(final long expectedCount) throws InterruptedException\n    {\n        while (batchEventProcessor.getSequence().get() != expectedCount)\n        {\n            Thread.sleep(1);\n        }\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        OneToOneSequencedBatchThroughputTest test = new OneToOneSequencedBatchThroughputTest();\n        test.testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/sequenced/OneToOneSequencedLongArrayThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.sequenced;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.support.LongArrayEventHandler;\nimport com.lmax.disruptor.support.PerfTestUtil;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static com.lmax.disruptor.RingBuffer.createSingleProducer;\n\n/**\n * <pre>\n * UniCast a series of items between 1 publisher and 1 event processor.\n *\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *\n * Disruptor:\n * ==========\n *              track to prevent wrap\n *              +------------------+\n *              |                  |\n *              |                  v\n * +----+    +====+    +====+   +-----+\n * | P1 |--->| RB |<---| SB |   | EP1 |\n * +----+    +====+    +====+   +-----+\n *      claim      get    ^        |\n *                        |        |\n *                        +--------+\n *                          waitFor\n *\n * P1  - Publisher 1\n * RB  - RingBuffer\n * SB  - SequenceBarrier\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class OneToOneSequencedLongArrayThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int BUFFER_SIZE = 1024 * 1;\n    private static final long ITERATIONS = 1000L * 1000L * 1L;\n    private static final int ARRAY_SIZE = 2 * 1024;\n    private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);\n\n    private static final EventFactory<long[]> FACTORY = () -> new long[ARRAY_SIZE];\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final RingBuffer<long[]> ringBuffer =\n        createSingleProducer(FACTORY, BUFFER_SIZE, new YieldingWaitStrategy());\n    private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n    private final LongArrayEventHandler handler = new LongArrayEventHandler();\n    private final BatchEventProcessor<long[]> batchEventProcessor =\n            new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, handler);\n\n    {\n        ringBuffer.addGatingSequences(batchEventProcessor.getSequence());\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 2;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws InterruptedException\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        final CountDownLatch latch = new CountDownLatch(1);\n        long expectedCount = batchEventProcessor.getSequence().get() + ITERATIONS;\n        handler.reset(latch, ITERATIONS);\n        executor.submit(batchEventProcessor);\n        long start = System.currentTimeMillis();\n\n        final RingBuffer<long[]> rb = ringBuffer;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long next = rb.next();\n            long[] event = rb.get(next);\n            for (int j = 0; j < event.length; j++)\n            {\n                event[j] = i;\n            }\n            rb.publish(next);\n        }\n\n        latch.await();\n        perfTestContext.setDisruptorOps((ITERATIONS * ARRAY_SIZE * 1000L) / (System.currentTimeMillis() - start));\n        perfTestContext.setBatchData(handler.getBatchesProcessed(), ITERATIONS);\n        waitForEventProcessorSequence(expectedCount);\n        batchEventProcessor.halt();\n\n        PerfTestUtil.failIf(0, handler.getValue());\n\n        return perfTestContext;\n    }\n\n    private void waitForEventProcessorSequence(final long expectedCount) throws InterruptedException\n    {\n        while (batchEventProcessor.getSequence().get() != expectedCount)\n        {\n            Thread.sleep(1);\n        }\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        OneToOneSequencedLongArrayThroughputTest test = new OneToOneSequencedLongArrayThroughputTest();\n        test.testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/sequenced/OneToOneSequencedPollerThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.sequenced;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.EventPoller;\nimport com.lmax.disruptor.EventPoller.PollState;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.support.PerfTestUtil;\nimport com.lmax.disruptor.support.ValueEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport com.lmax.disruptor.util.PaddedLong;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static com.lmax.disruptor.RingBuffer.createSingleProducer;\nimport static com.lmax.disruptor.support.PerfTestUtil.failIfNot;\n\n/**\n * <pre>\n * UniCast a series of items between 1 publisher and 1 event processor.\n *\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *\n * Disruptor:\n * ==========\n *              track to prevent wrap\n *              +------------------+\n *              |                  |\n *              |                  v\n * +----+    +====+    +====+   +-----+\n * | P1 |--->| RB |<---| SB |   | EP1 |\n * +----+    +====+    +====+   +-----+\n *      claim      get    ^        |\n *                        |        |\n *                        +--------+\n *                          waitFor\n *\n * P1  - Publisher 1\n * RB  - RingBuffer\n * SB  - SequenceBarrier\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class OneToOneSequencedPollerThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 100L;\n    private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);\n    private final long expectedResult = PerfTestUtil.accumulatedAddition(ITERATIONS);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final RingBuffer<ValueEvent> ringBuffer =\n        createSingleProducer(ValueEvent.EVENT_FACTORY, BUFFER_SIZE, new YieldingWaitStrategy());\n\n    private final EventPoller<ValueEvent> poller = ringBuffer.newPoller();\n    private final PollRunnable pollRunnable = new PollRunnable(poller);\n\n    {\n        ringBuffer.addGatingSequences(poller.getSequence());\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 2;\n    }\n\n    private static class PollRunnable implements Runnable, EventPoller.Handler<ValueEvent>\n    {\n        private final EventPoller<ValueEvent> poller;\n        private volatile boolean running = true;\n        private final PaddedLong value = new PaddedLong();\n        private final PaddedLong batchesProcessed = new PaddedLong();\n        private CountDownLatch latch;\n        private long count;\n\n        PollRunnable(final EventPoller<ValueEvent> poller)\n        {\n            this.poller = poller;\n        }\n\n        @Override\n        public void run()\n        {\n            try\n            {\n                while (running)\n                {\n                    if (PollState.PROCESSING != poller.poll(this))\n                    {\n                        Thread.yield();\n                    }\n                }\n            }\n            catch (Exception e)\n            {\n                e.printStackTrace();\n            }\n        }\n\n        @Override\n        public boolean onEvent(final ValueEvent event, final long sequence, final boolean endOfBatch)\n        {\n            value.set(value.get() + event.getValue());\n\n            if (count == sequence)\n            {\n                latch.countDown();\n            }\n\n            return true;\n        }\n\n        public void halt()\n        {\n            running = false;\n        }\n\n        public void reset(final CountDownLatch latch, final long expectedCount)\n        {\n            value.set(0L);\n            this.latch = latch;\n            count = expectedCount;\n            batchesProcessed.set(0);\n            running = true;\n        }\n\n        public long getValue()\n        {\n            return value.get();\n        }\n\n        public long getBatchesProcessed()\n        {\n            return batchesProcessed.get();\n        }\n\n        public void onBatchStart(final long batchSize)\n        {\n            batchesProcessed.increment();\n        }\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws InterruptedException\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        final CountDownLatch latch = new CountDownLatch(1);\n        long expectedCount = poller.getSequence().get() + ITERATIONS;\n        pollRunnable.reset(latch, expectedCount);\n        executor.submit(pollRunnable);\n        long start = System.currentTimeMillis();\n\n        final RingBuffer<ValueEvent> rb = ringBuffer;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long next = rb.next();\n            rb.get(next).setValue(i);\n            rb.publish(next);\n        }\n\n        latch.await();\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n        perfTestContext.setBatchData(pollRunnable.getBatchesProcessed(), ITERATIONS);\n        waitForEventProcessorSequence(expectedCount);\n        pollRunnable.halt();\n\n        failIfNot(expectedResult, pollRunnable.getValue());\n\n        return perfTestContext;\n    }\n\n    private void waitForEventProcessorSequence(final long expectedCount) throws InterruptedException\n    {\n        while (poller.getSequence().get() != expectedCount)\n        {\n            Thread.sleep(1);\n        }\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        OneToOneSequencedPollerThroughputTest test = new OneToOneSequencedPollerThroughputTest();\n        test.testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/sequenced/OneToOneSequencedThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.sequenced;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.support.PerfTestUtil;\nimport com.lmax.disruptor.support.ValueAdditionEventHandler;\nimport com.lmax.disruptor.support.ValueEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static com.lmax.disruptor.RingBuffer.createSingleProducer;\nimport static com.lmax.disruptor.support.PerfTestUtil.failIfNot;\n\n/**\n * <pre>\n * UniCast a series of items between 1 publisher and 1 event processor.\n *\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *\n * Disruptor:\n * ==========\n *              track to prevent wrap\n *              +------------------+\n *              |                  |\n *              |                  v\n * +----+    +====+    +====+   +-----+\n * | P1 |--->| RB |<---| SB |   | EP1 |\n * +----+    +====+    +====+   +-----+\n *      claim      get    ^        |\n *                        |        |\n *                        +--------+\n *                          waitFor\n *\n * P1  - Publisher 1\n * RB  - RingBuffer\n * SB  - SequenceBarrier\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class OneToOneSequencedThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 100L;\n    private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);\n    private final long expectedResult = PerfTestUtil.accumulatedAddition(ITERATIONS);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final RingBuffer<ValueEvent> ringBuffer =\n        createSingleProducer(ValueEvent.EVENT_FACTORY, BUFFER_SIZE, new YieldingWaitStrategy());\n    private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n    private final ValueAdditionEventHandler handler = new ValueAdditionEventHandler();\n    private final BatchEventProcessor<ValueEvent> batchEventProcessor =\n            new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, handler);\n\n    {\n        ringBuffer.addGatingSequences(batchEventProcessor.getSequence());\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 2;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws InterruptedException\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        final CountDownLatch latch = new CountDownLatch(1);\n        long expectedCount = batchEventProcessor.getSequence().get() + ITERATIONS;\n        handler.reset(latch, expectedCount);\n        executor.submit(batchEventProcessor);\n        long start = System.currentTimeMillis();\n\n        final RingBuffer<ValueEvent> rb = ringBuffer;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long next = rb.next();\n            rb.get(next).setValue(i);\n            rb.publish(next);\n        }\n\n        latch.await();\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n        perfTestContext.setBatchData(handler.getBatchesProcessed(), ITERATIONS);\n        waitForEventProcessorSequence(expectedCount);\n        batchEventProcessor.halt();\n\n        failIfNot(expectedResult, handler.getValue());\n\n        return perfTestContext;\n    }\n\n    private void waitForEventProcessorSequence(final long expectedCount) throws InterruptedException\n    {\n        while (batchEventProcessor.getSequence().get() != expectedCount)\n        {\n            Thread.sleep(1);\n        }\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        OneToOneSequencedThroughputTest test = new OneToOneSequencedThroughputTest();\n        test.testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/sequenced/OneToThreeDiamondSequencedThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.sequenced;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.support.FizzBuzzEvent;\nimport com.lmax.disruptor.support.FizzBuzzEventHandler;\nimport com.lmax.disruptor.support.FizzBuzzStep;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static com.lmax.disruptor.RingBuffer.createSingleProducer;\nimport static com.lmax.disruptor.support.PerfTestUtil.failIfNot;\n\n/**\n * <pre>\n * Produce an event replicated to two event processors and fold back to a single third event processor.\n *\n *           +-----+\n *    +----->| EP1 |------+\n *    |      +-----+      |\n *    |                   v\n * +----+              +-----+\n * | P1 |              | EP3 |\n * +----+              +-----+\n *    |                   ^\n *    |      +-----+      |\n *    +----->| EP2 |------+\n *           +-----+\n *\n * Disruptor:\n * ==========\n *                    track to prevent wrap\n *              +-------------------------------+\n *              |                               |\n *              |                               v\n * +----+    +====+               +=====+    +-----+\n * | P1 |--->| RB |<--------------| SB2 |<---| EP3 |\n * +----+    +====+               +=====+    +-----+\n *      claim   ^  get               |   waitFor\n *              |                    |\n *           +=====+    +-----+      |\n *           | SB1 |<---| EP1 |<-----+\n *           +=====+    +-----+      |\n *              ^                    |\n *              |       +-----+      |\n *              +-------| EP2 |<-----+\n *             waitFor  +-----+\n *\n * P1  - Publisher 1\n * RB  - RingBuffer\n * SB1 - SequenceBarrier 1\n * EP1 - EventProcessor 1\n * EP2 - EventProcessor 2\n * SB2 - SequenceBarrier 2\n * EP3 - EventProcessor 3\n *\n * </pre>\n */\npublic final class OneToThreeDiamondSequencedThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int NUM_EVENT_PROCESSORS = 3;\n    private static final int BUFFER_SIZE = 1024 * 8;\n    private static final long ITERATIONS = 1000L * 1000L * 100L;\n    private final ExecutorService executor = Executors.newFixedThreadPool(NUM_EVENT_PROCESSORS, DaemonThreadFactory.INSTANCE);\n\n    private final long expectedResult;\n\n    {\n        long temp = 0L;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            boolean fizz = 0 == (i % 3L);\n            boolean buzz = 0 == (i % 5L);\n\n            if (fizz && buzz)\n            {\n                ++temp;\n            }\n        }\n\n        expectedResult = temp;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final RingBuffer<FizzBuzzEvent> ringBuffer =\n        createSingleProducer(FizzBuzzEvent.EVENT_FACTORY, BUFFER_SIZE, new YieldingWaitStrategy());\n\n    private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n\n    private final FizzBuzzEventHandler fizzHandler = new FizzBuzzEventHandler(FizzBuzzStep.FIZZ);\n    private final BatchEventProcessor<FizzBuzzEvent> batchProcessorFizz =\n            new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, fizzHandler);\n\n    private final FizzBuzzEventHandler buzzHandler = new FizzBuzzEventHandler(FizzBuzzStep.BUZZ);\n    private final BatchEventProcessor<FizzBuzzEvent> batchProcessorBuzz =\n            new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, buzzHandler);\n\n    private final SequenceBarrier sequenceBarrierFizzBuzz =\n        ringBuffer.newBarrier(batchProcessorFizz.getSequence(), batchProcessorBuzz.getSequence());\n\n    private final FizzBuzzEventHandler fizzBuzzHandler = new FizzBuzzEventHandler(FizzBuzzStep.FIZZ_BUZZ);\n    private final BatchEventProcessor<FizzBuzzEvent> batchProcessorFizzBuzz =\n            new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrierFizzBuzz, fizzBuzzHandler);\n\n    {\n        ringBuffer.addGatingSequences(batchProcessorFizzBuzz.getSequence());\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 4;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws Exception\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        CountDownLatch latch = new CountDownLatch(1);\n        fizzBuzzHandler.reset(latch, batchProcessorFizzBuzz.getSequence().get() + ITERATIONS);\n\n        executor.submit(batchProcessorFizz);\n        executor.submit(batchProcessorBuzz);\n        executor.submit(batchProcessorFizzBuzz);\n\n        long start = System.currentTimeMillis();\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long sequence = ringBuffer.next();\n            ringBuffer.get(sequence).setValue(i);\n            ringBuffer.publish(sequence);\n        }\n\n        latch.await();\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n\n        batchProcessorFizz.halt();\n        batchProcessorBuzz.halt();\n        batchProcessorFizzBuzz.halt();\n\n        failIfNot(expectedResult, fizzBuzzHandler.getFizzBuzzCounter());\n\n        return perfTestContext;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new OneToThreeDiamondSequencedThroughputTest().testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/sequenced/OneToThreePipelineSequencedThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.sequenced;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.support.FunctionEvent;\nimport com.lmax.disruptor.support.FunctionEventHandler;\nimport com.lmax.disruptor.support.FunctionStep;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static com.lmax.disruptor.RingBuffer.createSingleProducer;\nimport static com.lmax.disruptor.support.PerfTestUtil.failIfNot;\n\n/**\n * Pipeline a series of stages from a publisher to ultimate event processor.\n * Each event processor depends on the output of the event processor.\n *\n * <pre>{@code\n * +----+    +-----+    +-----+    +-----+\n * | P1 |--->| EP1 |--->| EP2 |--->| EP3 |\n * +----+    +-----+    +-----+    +-----+\n *\n * Disruptor:\n * ==========\n *                           track to prevent wrap\n *              +----------------------------------------------------------------+\n *              |                                                                |\n *              |                                                                v\n * +----+    +====+    +=====+    +-----+    +=====+    +-----+    +=====+    +-----+\n * | P1 |--->| RB |    | SB1 |<---| EP1 |<---| SB2 |<---| EP2 |<---| SB3 |<---| EP3 |\n * +----+    +====+    +=====+    +-----+    +=====+    +-----+    +=====+    +-----+\n *      claim   ^  get    |   waitFor           |   waitFor           |  waitFor\n *              |         |                     |                     |\n *              +---------+---------------------+---------------------+\n *\n * P1  - Publisher 1\n * RB  - RingBuffer\n * SB1 - SequenceBarrier 1\n * EP1 - EventProcessor 1\n * SB2 - SequenceBarrier 2\n * EP2 - EventProcessor 2\n * SB3 - SequenceBarrier 3\n * EP3 - EventProcessor 3\n * }</pre>\n */\npublic final class OneToThreePipelineSequencedThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int NUM_EVENT_PROCESSORS = 3;\n    private static final int BUFFER_SIZE = 1024 * 8;\n    private static final long ITERATIONS = 1000L * 1000L * 100L;\n    private final ExecutorService executor = Executors.newFixedThreadPool(NUM_EVENT_PROCESSORS, DaemonThreadFactory.INSTANCE);\n\n    private static final long OPERAND_TWO_INITIAL_VALUE = 777L;\n    private final long expectedResult;\n\n    {\n        long temp = 0L;\n        long operandTwo = OPERAND_TWO_INITIAL_VALUE;\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long stepOneResult = i + operandTwo--;\n            long stepTwoResult = stepOneResult + 3;\n\n            if ((stepTwoResult & 4L) == 4L)\n            {\n                ++temp;\n            }\n        }\n\n        expectedResult = temp;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final RingBuffer<FunctionEvent> ringBuffer =\n        createSingleProducer(FunctionEvent.EVENT_FACTORY, BUFFER_SIZE, new YieldingWaitStrategy());\n\n    private final SequenceBarrier stepOneSequenceBarrier = ringBuffer.newBarrier();\n    private final FunctionEventHandler stepOneFunctionHandler = new FunctionEventHandler(FunctionStep.ONE);\n    private final BatchEventProcessor<FunctionEvent> stepOneBatchProcessor =\n            new BatchEventProcessorBuilder().build(ringBuffer, stepOneSequenceBarrier, stepOneFunctionHandler);\n\n    private final SequenceBarrier stepTwoSequenceBarrier = ringBuffer.newBarrier(stepOneBatchProcessor.getSequence());\n    private final FunctionEventHandler stepTwoFunctionHandler = new FunctionEventHandler(FunctionStep.TWO);\n    private final BatchEventProcessor<FunctionEvent> stepTwoBatchProcessor =\n            new BatchEventProcessorBuilder().build(ringBuffer, stepTwoSequenceBarrier, stepTwoFunctionHandler);\n\n    private final SequenceBarrier stepThreeSequenceBarrier = ringBuffer.newBarrier(stepTwoBatchProcessor.getSequence());\n    private final FunctionEventHandler stepThreeFunctionHandler = new FunctionEventHandler(FunctionStep.THREE);\n    private final BatchEventProcessor<FunctionEvent> stepThreeBatchProcessor =\n            new BatchEventProcessorBuilder().build(ringBuffer, stepThreeSequenceBarrier, stepThreeFunctionHandler);\n\n    {\n        ringBuffer.addGatingSequences(stepThreeBatchProcessor.getSequence());\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 4;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws InterruptedException\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n\n        CountDownLatch latch = new CountDownLatch(1);\n        stepThreeFunctionHandler.reset(latch, stepThreeBatchProcessor.getSequence().get() + ITERATIONS);\n\n        executor.submit(stepOneBatchProcessor);\n        executor.submit(stepTwoBatchProcessor);\n        executor.submit(stepThreeBatchProcessor);\n\n        long start = System.currentTimeMillis();\n\n        long operandTwo = OPERAND_TWO_INITIAL_VALUE;\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long sequence = ringBuffer.next();\n            FunctionEvent event = ringBuffer.get(sequence);\n            event.setOperandOne(i);\n            event.setOperandTwo(operandTwo--);\n            ringBuffer.publish(sequence);\n        }\n\n        latch.await();\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n\n        stepOneBatchProcessor.halt();\n        stepTwoBatchProcessor.halt();\n        stepThreeBatchProcessor.halt();\n\n        failIfNot(expectedResult, stepThreeFunctionHandler.getStepThreeCounter());\n\n        return perfTestContext;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new OneToThreePipelineSequencedThroughputTest().testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/sequenced/OneToThreeSequencedThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.sequenced;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.support.Operation;\nimport com.lmax.disruptor.support.ValueEvent;\nimport com.lmax.disruptor.support.ValueMutationEventHandler;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static com.lmax.disruptor.RingBuffer.createSingleProducer;\nimport static com.lmax.disruptor.support.PerfTestUtil.failIfNot;\n\n/**\n * <pre>\n *\n * MultiCast a series of items between 1 publisher and 3 event processors.\n *\n *           +-----+\n *    +----->| EP1 |\n *    |      +-----+\n *    |\n * +----+    +-----+\n * | P1 |--->| EP2 |\n * +----+    +-----+\n *    |\n *    |      +-----+\n *    +----->| EP3 |\n *           +-----+\n *\n * Disruptor:\n * ==========\n *                             track to prevent wrap\n *             +--------------------+----------+----------+\n *             |                    |          |          |\n *             |                    v          v          v\n * +----+    +====+    +====+    +-----+    +-----+    +-----+\n * | P1 |--->| RB |<---| SB |    | EP1 |    | EP2 |    | EP3 |\n * +----+    +====+    +====+    +-----+    +-----+    +-----+\n *      claim      get    ^         |          |          |\n *                        |         |          |          |\n *                        +---------+----------+----------+\n *                                      waitFor\n *\n * P1  - Publisher 1\n * RB  - RingBuffer\n * SB  - SequenceBarrier\n * EP1 - EventProcessor 1\n * EP2 - EventProcessor 2\n * EP3 - EventProcessor 3\n *\n * </pre>\n */\npublic final class OneToThreeSequencedThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int NUM_EVENT_PROCESSORS = 3;\n    private static final int BUFFER_SIZE = 1024 * 8;\n    private static final long ITERATIONS = 1000L * 1000L * 100L;\n    private final ExecutorService executor = Executors.newFixedThreadPool(NUM_EVENT_PROCESSORS, DaemonThreadFactory.INSTANCE);\n\n    private final long[] results = new long[NUM_EVENT_PROCESSORS];\n\n    {\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            results[0] = Operation.ADDITION.op(results[0], i);\n            results[1] = Operation.SUBTRACTION.op(results[1], i);\n            results[2] = Operation.AND.op(results[2], i);\n        }\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final RingBuffer<ValueEvent> ringBuffer =\n        createSingleProducer(ValueEvent.EVENT_FACTORY, BUFFER_SIZE, new YieldingWaitStrategy());\n\n    private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n\n    private final ValueMutationEventHandler[] handlers = new ValueMutationEventHandler[NUM_EVENT_PROCESSORS];\n\n    {\n        handlers[0] = new ValueMutationEventHandler(Operation.ADDITION);\n        handlers[1] = new ValueMutationEventHandler(Operation.SUBTRACTION);\n        handlers[2] = new ValueMutationEventHandler(Operation.AND);\n    }\n\n    private final BatchEventProcessor<?>[] batchEventProcessors = new BatchEventProcessor[NUM_EVENT_PROCESSORS];\n\n    {\n        batchEventProcessors[0] = new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, handlers[0]);\n        batchEventProcessors[1] = new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, handlers[1]);\n        batchEventProcessors[2] = new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, handlers[2]);\n\n        ringBuffer.addGatingSequences(\n            batchEventProcessors[0].getSequence(),\n            batchEventProcessors[1].getSequence(),\n            batchEventProcessors[2].getSequence());\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 4;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws InterruptedException\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        CountDownLatch latch = new CountDownLatch(NUM_EVENT_PROCESSORS);\n        for (int i = 0; i < NUM_EVENT_PROCESSORS; i++)\n        {\n            handlers[i].reset(latch, batchEventProcessors[i].getSequence().get() + ITERATIONS);\n            executor.submit(batchEventProcessors[i]);\n        }\n\n        long start = System.currentTimeMillis();\n\n        for (long i = 0; i < ITERATIONS; i++)\n        {\n            long sequence = ringBuffer.next();\n            ringBuffer.get(sequence).setValue(i);\n            ringBuffer.publish(sequence);\n        }\n\n        latch.await();\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n        perfTestContext.setBatchData(sumBatches(handlers), ITERATIONS * handlers.length);\n        for (int i = 0; i < NUM_EVENT_PROCESSORS; i++)\n        {\n            batchEventProcessors[i].halt();\n            failIfNot(results[i], handlers[i].getValue());\n        }\n\n        return perfTestContext;\n    }\n\n    private long sumBatches(final ValueMutationEventHandler[] handlers)\n    {\n        long sum = 0;\n        for (ValueMutationEventHandler handler : handlers)\n        {\n            sum += handler.getBatchesProcessed();\n        }\n        return sum;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new OneToThreeSequencedThroughputTest().testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/sequenced/PingPongSequencedLatencyTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.sequenced;\n\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.BlockingWaitStrategy;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.support.ValueEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport org.HdrHistogram.Histogram;\n\nimport java.io.PrintStream;\nimport java.util.concurrent.BrokenBarrierException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static com.lmax.disruptor.RingBuffer.createSingleProducer;\n\n/**\n * <pre>\n *\n * Ping pongs between 2 event handlers and measures the latency of\n * a round trip.\n *\n * Disruptor:\n * ==========\n *               +----------+\n *               |          |\n *               |   get    V\n *  waitFor   +=====+    +=====+  claim\n *    +------>| SB2 |    | RB2 |<------+\n *    |       +=====+    +=====+       |\n *    |                                |\n * +-----+    +=====+    +=====+    +-----+\n * | EP1 |--->| RB1 |    | SB1 |<---| EP2 |\n * +-----+    +=====+    +=====+    +-----+\n *       claim   ^   get    |  waitFor\n *               |          |\n *               +----------+\n *\n * EP1 - Pinger\n * EP2 - Ponger\n * RB1 - PingBuffer\n * SB1 - PingBarrier\n * RB2 - PongBuffer\n * SB2 - PongBarrier\n *\n * </pre>\n *\n * <p>Note: <b>This test is only useful on a system using an invariant TSC in user space from the System.nanoTime() call.</b>\n */\npublic final class PingPongSequencedLatencyTest\n{\n    private static final int BUFFER_SIZE = 1024;\n    private static final long ITERATIONS = 100L * 1000L * 30L;\n    private static final long PAUSE_NANOS = 1000L;\n    private final ExecutorService executor = Executors.newCachedThreadPool(DaemonThreadFactory.INSTANCE);\n\n    private final Histogram histogram = new Histogram(10000000000L, 4);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final RingBuffer<ValueEvent> pingBuffer =\n        createSingleProducer(ValueEvent.EVENT_FACTORY, BUFFER_SIZE, new BlockingWaitStrategy());\n    private final RingBuffer<ValueEvent> pongBuffer =\n        createSingleProducer(ValueEvent.EVENT_FACTORY, BUFFER_SIZE, new BlockingWaitStrategy());\n\n    private final SequenceBarrier pongBarrier = pongBuffer.newBarrier();\n    private final Pinger pinger = new Pinger(pingBuffer, ITERATIONS, PAUSE_NANOS);\n    private final BatchEventProcessor<ValueEvent> pingProcessor =\n            new BatchEventProcessorBuilder().build(pongBuffer, pongBarrier, pinger);\n\n    private final SequenceBarrier pingBarrier = pingBuffer.newBarrier();\n    private final Ponger ponger = new Ponger(pongBuffer);\n    private final BatchEventProcessor<ValueEvent> pongProcessor =\n            new BatchEventProcessorBuilder().build(pingBuffer, pingBarrier, ponger);\n\n    {\n        pingBuffer.addGatingSequences(pongProcessor.getSequence());\n        pongBuffer.addGatingSequences(pingProcessor.getSequence());\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    public void shouldCompareDisruptorVsQueues() throws Exception\n    {\n        final int runs = 3;\n\n        for (int i = 0; i < runs; i++)\n        {\n            System.gc();\n            histogram.reset();\n\n            runDisruptorPass();\n\n            System.out.format(\"%s run %d Disruptor %s\\n\", getClass().getSimpleName(), Long.valueOf(i), histogram);\n            dumpHistogram(histogram, System.out);\n        }\n    }\n\n    private static void dumpHistogram(final Histogram histogram, final PrintStream out)\n    {\n        histogram.outputPercentileDistribution(out, 1, 1000.0);\n    }\n\n    private void runDisruptorPass() throws InterruptedException, BrokenBarrierException\n    {\n        final CountDownLatch latch = new CountDownLatch(1);\n        final CyclicBarrier barrier = new CyclicBarrier(3);\n        pinger.reset(barrier, latch, histogram);\n        ponger.reset(barrier);\n\n        executor.submit(pongProcessor);\n        executor.submit(pingProcessor);\n\n        barrier.await();\n        latch.await();\n\n        pingProcessor.halt();\n        pongProcessor.halt();\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        final PingPongSequencedLatencyTest test = new PingPongSequencedLatencyTest();\n        test.shouldCompareDisruptorVsQueues();\n    }\n\n    private static class Pinger implements EventHandler<ValueEvent>\n    {\n        private final RingBuffer<ValueEvent> buffer;\n        private final long maxEvents;\n        private final long pauseTimeNs;\n\n        private long counter = 0;\n        private CyclicBarrier barrier;\n        private CountDownLatch latch;\n        private Histogram histogram;\n        private long t0;\n\n        Pinger(final RingBuffer<ValueEvent> buffer, final long maxEvents, final long pauseTimeNs)\n        {\n            this.buffer = buffer;\n            this.maxEvents = maxEvents;\n            this.pauseTimeNs = pauseTimeNs;\n        }\n\n        @Override\n        public void onEvent(final ValueEvent event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            final long t1 = System.nanoTime();\n\n            histogram.recordValueWithExpectedInterval(t1 - t0, pauseTimeNs);\n\n            if (event.getValue() < maxEvents)\n            {\n                while (pauseTimeNs > (System.nanoTime() - t1))\n                {\n                    Thread.yield();\n                }\n\n                send();\n            }\n            else\n            {\n                latch.countDown();\n            }\n        }\n\n        private void send()\n        {\n            t0 = System.nanoTime();\n            final long next = buffer.next();\n            buffer.get(next).setValue(counter);\n            buffer.publish(next);\n\n            counter++;\n        }\n\n        @Override\n        public void onStart()\n        {\n            try\n            {\n                barrier.await();\n\n                Thread.sleep(1000);\n                send();\n            }\n            catch (final Exception e)\n            {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        public void onShutdown()\n        {\n        }\n\n        public void reset(final CyclicBarrier barrier, final CountDownLatch latch, final Histogram histogram)\n        {\n            this.histogram = histogram;\n            this.barrier = barrier;\n            this.latch = latch;\n\n            counter = 0;\n        }\n    }\n\n    private static class Ponger implements EventHandler<ValueEvent>\n    {\n        private final RingBuffer<ValueEvent> buffer;\n\n        private CyclicBarrier barrier;\n\n        Ponger(final RingBuffer<ValueEvent> buffer)\n        {\n            this.buffer = buffer;\n        }\n\n        @Override\n        public void onEvent(final ValueEvent event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            final long next = buffer.next();\n            buffer.get(next).setValue(event.getValue());\n            buffer.publish(next);\n        }\n\n        @Override\n        public void onStart()\n        {\n            try\n            {\n                barrier.await();\n            }\n            catch (final Exception e)\n            {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        public void onShutdown()\n        {\n        }\n\n        public void reset(final CyclicBarrier barrier)\n        {\n            this.barrier = barrier;\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/sequenced/ThreeToOneSequencedBatchThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.sequenced;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.BusySpinWaitStrategy;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.support.ValueAdditionEventHandler;\nimport com.lmax.disruptor.support.ValueBatchPublisher;\nimport com.lmax.disruptor.support.ValueEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport static com.lmax.disruptor.RingBuffer.createMultiProducer;\n\n/**\n * <pre>\n *\n * Sequence a series of events from multiple publishers going to one event processor.\n *\n * +----+\n * | P1 |------+\n * +----+      |\n *             v\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *             ^\n * +----+      |\n * | P3 |------+\n * +----+\n *\n * Disruptor:\n * ==========\n *             track to prevent wrap\n *             +--------------------+\n *             |                    |\n *             |                    v\n * +----+    +====+    +====+    +-----+\n * | P1 |--->| RB |<---| SB |    | EP1 |\n * +----+    +====+    +====+    +-----+\n *             ^   get    ^         |\n * +----+      |          |         |\n * | P2 |------+          +---------+\n * +----+      |            waitFor\n *             |\n * +----+      |\n * | P3 |------+\n * +----+\n *\n * P1  - Publisher 1\n * P2  - Publisher 2\n * P3  - Publisher 3\n * RB  - RingBuffer\n * SB  - SequenceBarrier\n * EP1 - EventProcessor 1\n *\n * </pre>\n *\n * @author mikeb01\n */\npublic final class ThreeToOneSequencedBatchThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int NUM_PUBLISHERS = 3;\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 100L;\n    private final ExecutorService executor = Executors.newFixedThreadPool(NUM_PUBLISHERS + 1, DaemonThreadFactory.INSTANCE);\n    private final CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM_PUBLISHERS + 1);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final RingBuffer<ValueEvent> ringBuffer =\n        createMultiProducer(ValueEvent.EVENT_FACTORY, BUFFER_SIZE, new BusySpinWaitStrategy());\n\n    private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n    private final ValueAdditionEventHandler handler = new ValueAdditionEventHandler();\n    private final BatchEventProcessor<ValueEvent> batchEventProcessor =\n            new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, handler);\n    private final ValueBatchPublisher[] valuePublishers = new ValueBatchPublisher[NUM_PUBLISHERS];\n\n    {\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            valuePublishers[i] = new ValueBatchPublisher(cyclicBarrier, ringBuffer, ITERATIONS / NUM_PUBLISHERS, 10);\n        }\n\n        ringBuffer.addGatingSequences(batchEventProcessor.getSequence());\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 4;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws Exception\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        final CountDownLatch latch = new CountDownLatch(1);\n        handler.reset(latch, batchEventProcessor.getSequence().get() + ((ITERATIONS / NUM_PUBLISHERS) * NUM_PUBLISHERS));\n\n        Future<?>[] futures = new Future[NUM_PUBLISHERS];\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            futures[i] = executor.submit(valuePublishers[i]);\n        }\n        executor.submit(batchEventProcessor);\n\n        long start = System.currentTimeMillis();\n        cyclicBarrier.await();\n\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            futures[i].get();\n        }\n\n        latch.await();\n\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n        perfTestContext.setBatchData(handler.getBatchesProcessed(), ITERATIONS);\n        batchEventProcessor.halt();\n\n        return perfTestContext;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new ThreeToOneSequencedBatchThroughputTest().testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/sequenced/ThreeToOneSequencedThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.sequenced;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.BusySpinWaitStrategy;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.support.ValueAdditionEventHandler;\nimport com.lmax.disruptor.support.ValueEvent;\nimport com.lmax.disruptor.support.ValuePublisher;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport static com.lmax.disruptor.RingBuffer.createMultiProducer;\n\n/**\n * <pre>\n *\n * Sequence a series of events from multiple publishers going to one event processor.\n *\n * +----+\n * | P1 |------+\n * +----+      |\n *             v\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *             ^\n * +----+      |\n * | P3 |------+\n * +----+\n *\n *\n * Disruptor:\n * ==========\n *             track to prevent wrap\n *             +--------------------+\n *             |                    |\n *             |                    v\n * +----+    +====+    +====+    +-----+\n * | P1 |--->| RB |<---| SB |    | EP1 |\n * +----+    +====+    +====+    +-----+\n *             ^   get    ^         |\n * +----+      |          |         |\n * | P2 |------+          +---------+\n * +----+      |            waitFor\n *             |\n * +----+      |\n * | P3 |------+\n * +----+\n *\n * P1  - Publisher 1\n * P2  - Publisher 2\n * P3  - Publisher 3\n * RB  - RingBuffer\n * SB  - SequenceBarrier\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class ThreeToOneSequencedThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int NUM_PUBLISHERS = 3;\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 20L;\n    private final ExecutorService executor =\n        Executors.newFixedThreadPool(NUM_PUBLISHERS + 1, DaemonThreadFactory.INSTANCE);\n    private final CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM_PUBLISHERS + 1);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    private final RingBuffer<ValueEvent> ringBuffer =\n        createMultiProducer(ValueEvent.EVENT_FACTORY, BUFFER_SIZE, new BusySpinWaitStrategy());\n\n    private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n    private final ValueAdditionEventHandler handler = new ValueAdditionEventHandler();\n    private final BatchEventProcessor<ValueEvent> batchEventProcessor =\n            new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, handler);\n    private final ValuePublisher[] valuePublishers = new ValuePublisher[NUM_PUBLISHERS];\n\n    {\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            valuePublishers[i] = new ValuePublisher(cyclicBarrier, ringBuffer, ITERATIONS / NUM_PUBLISHERS);\n        }\n\n        ringBuffer.addGatingSequences(batchEventProcessor.getSequence());\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 4;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws Exception\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        final CountDownLatch latch = new CountDownLatch(1);\n        handler\n            .reset(latch, batchEventProcessor.getSequence().get() + ((ITERATIONS / NUM_PUBLISHERS) * NUM_PUBLISHERS));\n\n        Future<?>[] futures = new Future[NUM_PUBLISHERS];\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            futures[i] = executor.submit(valuePublishers[i]);\n        }\n        executor.submit(batchEventProcessor);\n\n        long start = System.currentTimeMillis();\n        cyclicBarrier.await();\n\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            futures[i].get();\n        }\n\n        latch.await();\n\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n        perfTestContext.setBatchData(handler.getBatchesProcessed(), ITERATIONS);\n        batchEventProcessor.halt();\n\n        return perfTestContext;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new ThreeToOneSequencedThroughputTest().testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/sequenced/ThreeToThreeSequencedThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.sequenced;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.support.LongArrayEventHandler;\nimport com.lmax.disruptor.support.LongArrayPublisher;\nimport com.lmax.disruptor.support.MultiBufferBatchEventProcessor;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\n/**\n * <pre>\n *\n * Sequence a series of events from multiple publishers going to one event processor.\n *\n * Disruptor:\n * ==========\n *             track to prevent wrap\n *             +--------------------+\n *             |                    |\n *             |                    |\n * +----+    +====+    +====+       |\n * | P1 |--->| RB |--->| SB |--+    |\n * +----+    +====+    +====+  |    |\n *                             |    v\n * +----+    +====+    +====+  | +----+\n * | P2 |--->| RB |--->| SB |--+>| EP |\n * +----+    +====+    +====+  | +----+\n *                             |\n * +----+    +====+    +====+  |\n * | P3 |--->| RB |--->| SB |--+\n * +----+    +====+    +====+\n *\n * P1 - Publisher 1\n * P2 - Publisher 2\n * P3 - Publisher 3\n * RB - RingBuffer\n * SB - SequenceBarrier\n * EP - EventProcessor\n *\n * </pre>\n */\npublic final class ThreeToThreeSequencedThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int NUM_PUBLISHERS = 3;\n    private static final int ARRAY_SIZE = 3;\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 180L;\n    private final ExecutorService executor =\n        Executors.newFixedThreadPool(NUM_PUBLISHERS + 1, DaemonThreadFactory.INSTANCE);\n    private final CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM_PUBLISHERS + 1);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @SuppressWarnings(\"unchecked\")\n    private final RingBuffer<long[]>[] buffers = new RingBuffer[NUM_PUBLISHERS];\n    private final SequenceBarrier[] barriers = new SequenceBarrier[NUM_PUBLISHERS];\n    private final LongArrayPublisher[] valuePublishers = new LongArrayPublisher[NUM_PUBLISHERS];\n\n    private final LongArrayEventHandler handler = new LongArrayEventHandler();\n    private final MultiBufferBatchEventProcessor<long[]> batchEventProcessor;\n\n    private static final EventFactory<long[]> FACTORY = () -> new long[ARRAY_SIZE];\n\n    {\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            buffers[i] = RingBuffer.createSingleProducer(FACTORY, BUFFER_SIZE, new YieldingWaitStrategy());\n            barriers[i] = buffers[i].newBarrier();\n            valuePublishers[i] = new LongArrayPublisher(\n                cyclicBarrier,\n                buffers[i],\n                ITERATIONS / NUM_PUBLISHERS,\n                ARRAY_SIZE);\n        }\n\n        batchEventProcessor = new MultiBufferBatchEventProcessor<>(buffers, barriers, handler);\n\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            buffers[i].addGatingSequences(batchEventProcessor.getSequences()[i]);\n        }\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 4;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws Exception\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        final CountDownLatch latch = new CountDownLatch(1);\n        handler.reset(latch, ITERATIONS);\n\n        Future<?>[] futures = new Future[NUM_PUBLISHERS];\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            futures[i] = executor.submit(valuePublishers[i]);\n        }\n        executor.submit(batchEventProcessor);\n\n        long start = System.currentTimeMillis();\n        cyclicBarrier.await();\n\n        for (int i = 0; i < NUM_PUBLISHERS; i++)\n        {\n            futures[i].get();\n        }\n\n        latch.await();\n\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L * ARRAY_SIZE) / (System.currentTimeMillis() - start));\n        perfTestContext.setBatchData(handler.getBatchesProcessed(), ITERATIONS * ARRAY_SIZE);\n        batchEventProcessor.halt();\n\n        return perfTestContext;\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        new ThreeToThreeSequencedThroughputTest().testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/EventCountingQueueProcessor.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.util.PaddedLong;\n\nimport java.util.concurrent.BlockingQueue;\n\npublic final class EventCountingQueueProcessor implements Runnable\n{\n    private volatile boolean running;\n    private final BlockingQueue<Long> blockingQueue;\n    private final PaddedLong[] counters;\n    private final int index;\n\n    public EventCountingQueueProcessor(\n        final BlockingQueue<Long> blockingQueue, final PaddedLong[] counters, final int index)\n    {\n        this.blockingQueue = blockingQueue;\n        this.counters = counters;\n        this.index = index;\n    }\n\n    public void halt()\n    {\n        running = false;\n    }\n\n    @Override\n    public void run()\n    {\n        running = true;\n        while (running)\n        {\n            try\n            {\n                blockingQueue.take();\n                counters[index].set(counters[index].get() + 1L);\n            }\n            catch (InterruptedException ex)\n            {\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/FizzBuzzEvent.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventFactory;\n\npublic final class FizzBuzzEvent\n{\n    private boolean fizz = false;\n    private boolean buzz = false;\n    private long value = 0;\n\n    public long getValue()\n    {\n        return value;\n    }\n\n    public void setValue(final long value)\n    {\n        fizz = false;\n        buzz = false;\n        this.value = value;\n    }\n\n    public boolean isFizz()\n    {\n        return fizz;\n    }\n\n    public void setFizz(final boolean fizz)\n    {\n        this.fizz = fizz;\n    }\n\n    public boolean isBuzz()\n    {\n        return buzz;\n    }\n\n    public void setBuzz(final boolean buzz)\n    {\n        this.buzz = buzz;\n    }\n\n    public static final EventFactory<FizzBuzzEvent> EVENT_FACTORY = () -> new FizzBuzzEvent();\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/FizzBuzzEventHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.util.PaddedLong;\n\nimport java.util.concurrent.CountDownLatch;\n\npublic final class FizzBuzzEventHandler implements EventHandler<FizzBuzzEvent>\n{\n    private final FizzBuzzStep fizzBuzzStep;\n    private final PaddedLong fizzBuzzCounter = new PaddedLong();\n    private long count;\n    private CountDownLatch latch;\n\n    public FizzBuzzEventHandler(final FizzBuzzStep fizzBuzzStep)\n    {\n        this.fizzBuzzStep = fizzBuzzStep;\n    }\n\n    public void reset(final CountDownLatch latch, final long expectedCount)\n    {\n        fizzBuzzCounter.set(0L);\n        this.latch = latch;\n        count = expectedCount;\n    }\n\n    public long getFizzBuzzCounter()\n    {\n        return fizzBuzzCounter.get();\n    }\n\n    @Override\n    public void onEvent(final FizzBuzzEvent event, final long sequence, final boolean endOfBatch) throws Exception\n    {\n        switch (fizzBuzzStep)\n        {\n            case FIZZ:\n                if (0 == (event.getValue() % 3))\n                {\n                    event.setFizz(true);\n                }\n                break;\n\n            case BUZZ:\n                if (0 == (event.getValue() % 5))\n                {\n                    event.setBuzz(true);\n                }\n                break;\n\n            case FIZZ_BUZZ:\n                if (event.isFizz() && event.isBuzz())\n                {\n                    fizzBuzzCounter.set(fizzBuzzCounter.get() + 1L);\n                }\n                break;\n        }\n\n        if (latch != null && count == sequence)\n        {\n            latch.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/FizzBuzzQueueProcessor.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\n\npublic final class FizzBuzzQueueProcessor implements Runnable\n{\n    private final FizzBuzzStep fizzBuzzStep;\n    private final BlockingQueue<Long> fizzInputQueue;\n    private final BlockingQueue<Long> buzzInputQueue;\n    private final BlockingQueue<Boolean> fizzOutputQueue;\n    private final BlockingQueue<Boolean> buzzOutputQueue;\n    private final long count;\n\n    private volatile boolean running;\n    private long fizzBuzzCounter = 0;\n    private long sequence;\n    private CountDownLatch latch = null;\n\n    public FizzBuzzQueueProcessor(\n        final FizzBuzzStep fizzBuzzStep,\n        final BlockingQueue<Long> fizzInputQueue,\n        final BlockingQueue<Long> buzzInputQueue,\n        final BlockingQueue<Boolean> fizzOutputQueue,\n        final BlockingQueue<Boolean> buzzOutputQueue, final long count)\n    {\n        this.fizzBuzzStep = fizzBuzzStep;\n\n        this.fizzInputQueue = fizzInputQueue;\n        this.buzzInputQueue = buzzInputQueue;\n        this.fizzOutputQueue = fizzOutputQueue;\n        this.buzzOutputQueue = buzzOutputQueue;\n        this.count = count;\n    }\n\n    public long getFizzBuzzCounter()\n    {\n        return fizzBuzzCounter;\n    }\n\n    public void reset(final CountDownLatch latch)\n    {\n        fizzBuzzCounter = 0L;\n        sequence = 0L;\n        this.latch = latch;\n    }\n\n    public void halt()\n    {\n        running = false;\n    }\n\n    @Override\n    public void run()\n    {\n        running = true;\n        while (true)\n        {\n            try\n            {\n                switch (fizzBuzzStep)\n                {\n                    case FIZZ:\n                    {\n                        Long value = fizzInputQueue.take();\n                        fizzOutputQueue.put(Boolean.valueOf(0 == (value.longValue() % 3)));\n                        break;\n                    }\n\n                    case BUZZ:\n                    {\n                        Long value = buzzInputQueue.take();\n                        buzzOutputQueue.put(Boolean.valueOf(0 == (value.longValue() % 5)));\n                        break;\n                    }\n\n                    case FIZZ_BUZZ:\n                    {\n                        final boolean fizz = fizzOutputQueue.take().booleanValue();\n                        final boolean buzz = buzzOutputQueue.take().booleanValue();\n                        if (fizz && buzz)\n                        {\n                            ++fizzBuzzCounter;\n                        }\n                        break;\n                    }\n                }\n\n                if (null != latch && sequence++ == count)\n                {\n                    latch.countDown();\n                }\n            }\n            catch (InterruptedException ex)\n            {\n                if (!running)\n                {\n                    break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/FizzBuzzStep.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\npublic enum FizzBuzzStep\n{\n    FIZZ,\n    BUZZ,\n    FIZZ_BUZZ,\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/FunctionEvent.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventFactory;\n\npublic final class FunctionEvent\n{\n    private long operandOne;\n    private long operandTwo;\n    private long stepOneResult;\n    private long stepTwoResult;\n\n    public long getOperandOne()\n    {\n        return operandOne;\n    }\n\n    public void setOperandOne(final long operandOne)\n    {\n        this.operandOne = operandOne;\n    }\n\n    public long getOperandTwo()\n    {\n        return operandTwo;\n    }\n\n    public void setOperandTwo(final long operandTwo)\n    {\n        this.operandTwo = operandTwo;\n    }\n\n    public long getStepOneResult()\n    {\n        return stepOneResult;\n    }\n\n    public void setStepOneResult(final long stepOneResult)\n    {\n        this.stepOneResult = stepOneResult;\n    }\n\n    public long getStepTwoResult()\n    {\n        return stepTwoResult;\n    }\n\n    public void setStepTwoResult(final long stepTwoResult)\n    {\n        this.stepTwoResult = stepTwoResult;\n    }\n\n    public static final EventFactory<FunctionEvent> EVENT_FACTORY = () -> new FunctionEvent();\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/FunctionEventHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.util.PaddedLong;\n\nimport java.util.concurrent.CountDownLatch;\n\npublic final class FunctionEventHandler implements EventHandler<FunctionEvent>\n{\n    private final FunctionStep functionStep;\n    private final PaddedLong stepThreeCounter = new PaddedLong();\n    private long count;\n    private CountDownLatch latch;\n\n    public FunctionEventHandler(final FunctionStep functionStep)\n    {\n        this.functionStep = functionStep;\n    }\n\n    public long getStepThreeCounter()\n    {\n        return stepThreeCounter.get();\n    }\n\n    public void reset(final CountDownLatch latch, final long expectedCount)\n    {\n        stepThreeCounter.set(0L);\n        this.latch = latch;\n        count = expectedCount;\n    }\n\n    @Override\n    public void onEvent(final FunctionEvent event, final long sequence, final boolean endOfBatch) throws Exception\n    {\n        switch (functionStep)\n        {\n            case ONE:\n                event.setStepOneResult(event.getOperandOne() + event.getOperandTwo());\n                break;\n\n            case TWO:\n                event.setStepTwoResult(event.getStepOneResult() + 3L);\n                break;\n\n            case THREE:\n                if ((event.getStepTwoResult() & 4L) == 4L)\n                {\n                    stepThreeCounter.set(stepThreeCounter.get() + 1L);\n                }\n                break;\n        }\n\n        if (latch != null && count == sequence)\n        {\n            latch.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/FunctionQueueProcessor.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\n\npublic final class FunctionQueueProcessor implements Runnable\n{\n    private final FunctionStep functionStep;\n    private final BlockingQueue<long[]> stepOneQueue;\n    private final BlockingQueue<Long> stepTwoQueue;\n    private final BlockingQueue<Long> stepThreeQueue;\n    private final long count;\n\n    private volatile boolean running;\n    private long stepThreeCounter;\n    private long sequence;\n    private CountDownLatch latch;\n\n    public FunctionQueueProcessor(\n        final FunctionStep functionStep,\n        final BlockingQueue<long[]> stepOneQueue,\n        final BlockingQueue<Long> stepTwoQueue,\n        final BlockingQueue<Long> stepThreeQueue,\n        final long count)\n    {\n        this.functionStep = functionStep;\n        this.stepOneQueue = stepOneQueue;\n        this.stepTwoQueue = stepTwoQueue;\n        this.stepThreeQueue = stepThreeQueue;\n        this.count = count;\n    }\n\n    public long getStepThreeCounter()\n    {\n        return stepThreeCounter;\n    }\n\n    public void reset(final CountDownLatch latch)\n    {\n        stepThreeCounter = 0L;\n        sequence = 0L;\n        this.latch = latch;\n    }\n\n    public void halt()\n    {\n        running = false;\n    }\n\n    @Override\n    public void run()\n    {\n        running = true;\n        while (true)\n        {\n            try\n            {\n                switch (functionStep)\n                {\n                    case ONE:\n                    {\n                        long[] values = stepOneQueue.take();\n                        stepTwoQueue.put(Long.valueOf(values[0] + values[1]));\n                        break;\n                    }\n\n                    case TWO:\n                    {\n                        Long value = stepTwoQueue.take();\n                        stepThreeQueue.put(Long.valueOf(value.longValue() + 3));\n                        break;\n                    }\n\n                    case THREE:\n                    {\n                        Long value = stepThreeQueue.take();\n                        long testValue = value.longValue();\n                        if ((testValue & 4L) == 4L)\n                        {\n                            ++stepThreeCounter;\n                        }\n                        break;\n                    }\n                }\n\n                if (null != latch && sequence++ == count)\n                {\n                    latch.countDown();\n                }\n            }\n            catch (InterruptedException ex)\n            {\n                if (!running)\n                {\n                    break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/FunctionStep.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\npublic enum FunctionStep\n{\n    ONE,\n    TWO,\n    THREE\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/LongArrayEventHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.util.PaddedLong;\n\nimport java.util.concurrent.CountDownLatch;\n\npublic final class LongArrayEventHandler implements EventHandler<long[]>\n{\n    private final PaddedLong value = new PaddedLong();\n    private final PaddedLong batchesProcessed = new PaddedLong();\n    private long count;\n    private CountDownLatch latch;\n\n    public long getValue()\n    {\n        return value.get();\n    }\n\n    public long getBatchesProcessed()\n    {\n        return batchesProcessed.get();\n    }\n\n    public void reset(final CountDownLatch latch, final long expectedCount)\n    {\n        value.set(0L);\n        this.latch = latch;\n        count = expectedCount;\n        batchesProcessed.set(0);\n    }\n\n    @Override\n    public void onEvent(final long[] event, final long sequence, final boolean endOfBatch) throws Exception\n    {\n        for (int i = 0; i < event.length; i++)\n        {\n            value.set(value.get() + event[i]);\n        }\n\n        if (--count == 0)\n        {\n            latch.countDown();\n        }\n    }\n\n    @Override\n    public void onBatchStart(final long batchSize, final long queueDepth)\n    {\n        batchesProcessed.increment();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/LongArrayPublisher.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.RingBuffer;\n\nimport java.util.concurrent.CyclicBarrier;\n\npublic final class LongArrayPublisher implements Runnable\n{\n    private final CyclicBarrier cyclicBarrier;\n    private final RingBuffer<long[]> ringBuffer;\n    private final long iterations;\n    private final long arraySize;\n\n    public LongArrayPublisher(\n        final CyclicBarrier cyclicBarrier,\n        final RingBuffer<long[]> ringBuffer,\n        final long iterations,\n        final long arraySize)\n    {\n        this.cyclicBarrier = cyclicBarrier;\n        this.ringBuffer = ringBuffer;\n        this.iterations = iterations;\n        this.arraySize = arraySize;\n    }\n\n    @Override\n    public void run()\n    {\n        try\n        {\n            cyclicBarrier.await();\n\n            for (long i = 0; i < iterations; i++)\n            {\n                long sequence = ringBuffer.next();\n                long[] event = ringBuffer.get(sequence);\n                for (int j = 0; j < arraySize; j++)\n                {\n                    event[j] = i + j;\n                }\n                ringBuffer.publish(sequence);\n            }\n        }\n        catch (Exception ex)\n        {\n            throw new RuntimeException(ex);\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/MultiBufferBatchEventProcessor.java",
    "content": "package com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.AlertException;\nimport com.lmax.disruptor.DataProvider;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.TimeoutException;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class MultiBufferBatchEventProcessor<T>\n    implements EventProcessor\n{\n    private final AtomicBoolean isRunning = new AtomicBoolean(false);\n    private final DataProvider<T>[] providers;\n    private final SequenceBarrier[] barriers;\n    private final EventHandler<T> handler;\n    private final Sequence[] sequences;\n    private long count;\n\n    public MultiBufferBatchEventProcessor(\n        final DataProvider<T>[] providers,\n        final SequenceBarrier[] barriers,\n        final EventHandler<T> handler)\n    {\n        if (providers.length != barriers.length)\n        {\n            throw new IllegalArgumentException();\n        }\n\n        this.providers = providers;\n        this.barriers = barriers;\n        this.handler = handler;\n\n        this.sequences = new Sequence[providers.length];\n        for (int i = 0; i < sequences.length; i++)\n        {\n            sequences[i] = new Sequence(-1);\n        }\n    }\n\n    @Override\n    public void run()\n    {\n        if (!isRunning.compareAndSet(false, true))\n        {\n            throw new RuntimeException(\"Already running\");\n        }\n\n        for (SequenceBarrier barrier : barriers)\n        {\n            barrier.clearAlert();\n        }\n\n        final int barrierLength = barriers.length;\n\n        while (true)\n        {\n            try\n            {\n                for (int i = 0; i < barrierLength; i++)\n                {\n                    long available = barriers[i].waitFor(-1);\n                    Sequence sequence = sequences[i];\n\n                    long nextSequence = sequence.get() + 1;\n\n                    for (long l = nextSequence; l <= available; l++)\n                    {\n                        handler.onEvent(providers[i].get(l), l, nextSequence == available);\n                    }\n\n                    sequence.set(available);\n\n                    count += available - nextSequence + 1;\n                }\n\n                Thread.yield();\n            }\n            catch (AlertException e)\n            {\n                if (!isRunning())\n                {\n                    break;\n                }\n            }\n            catch (InterruptedException e)\n            {\n                e.printStackTrace();\n            }\n            catch (TimeoutException e)\n            {\n                e.printStackTrace();\n            }\n            catch (Exception e)\n            {\n                e.printStackTrace();\n                break;\n            }\n        }\n    }\n\n    @Override\n    public Sequence getSequence()\n    {\n        throw new UnsupportedOperationException();\n    }\n\n    public long getCount()\n    {\n        return count;\n    }\n\n    public Sequence[] getSequences()\n    {\n        return sequences;\n    }\n\n    @Override\n    public void halt()\n    {\n        isRunning.set(false);\n        barriers[0].alert();\n    }\n\n    @Override\n    public boolean isRunning()\n    {\n        return isRunning.get();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/Operation.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\npublic enum Operation\n{\n    ADDITION\n        {\n            @Override\n            public long op(final long lhs, final long rhs)\n            {\n                return lhs + rhs;\n            }\n        },\n\n    SUBTRACTION\n        {\n            @Override\n            public long op(final long lhs, final long rhs)\n            {\n                return lhs - rhs;\n            }\n        },\n\n    AND\n        {\n            @Override\n            public long op(final long lhs, final long rhs)\n            {\n                return lhs & rhs;\n            }\n        };\n\n    public abstract long op(long lhs, long rhs);\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/PerfTestUtil.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\npublic final class PerfTestUtil\n{\n    public static long accumulatedAddition(final long iterations)\n    {\n        long temp = 0L;\n        for (long i = 0L; i < iterations; i++)\n        {\n            temp += i;\n        }\n\n        return temp;\n    }\n\n    public static void failIf(final long a, final long b)\n    {\n        if (a == b)\n        {\n            throw new RuntimeException();\n        }\n    }\n\n    public static void failIfNot(final long a, final long b)\n    {\n        if (a != b)\n        {\n            throw new RuntimeException();\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/ValueAdditionBatchQueueProcessor.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport java.util.ArrayList;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\n\npublic final class ValueAdditionBatchQueueProcessor implements Runnable\n{\n    private volatile boolean running;\n    private long value;\n    private long sequence;\n    private CountDownLatch latch;\n\n    private final BlockingQueue<Long> blockingQueue;\n    private final ArrayList<Long> batch = new ArrayList<>(100);\n    private final long count;\n\n    public ValueAdditionBatchQueueProcessor(final BlockingQueue<Long> blockingQueue, final long count)\n    {\n        this.blockingQueue = blockingQueue;\n        this.count = count;\n    }\n\n    public long getValue()\n    {\n        return value;\n    }\n\n    public void reset(final CountDownLatch latch)\n    {\n        value = 0L;\n        sequence = 0L;\n        this.latch = latch;\n    }\n\n    public void halt()\n    {\n        running = false;\n    }\n\n    @Override\n    public void run()\n    {\n        running = true;\n        while (true)\n        {\n            try\n            {\n                long v = blockingQueue.take();\n                sequence++;\n\n                this.value += v;\n\n                int c = blockingQueue.drainTo(batch, 100);\n                sequence += c;\n\n                v = 0;\n                for (int i = 0, n = batch.size(); i < n; i++)\n                {\n                    v += batch.get(i);\n                }\n\n                this.value += v;\n\n                batch.clear();\n\n                if (sequence == count)\n                {\n                    latch.countDown();\n                }\n            }\n            catch (InterruptedException ex)\n            {\n                if (!running)\n                {\n                    break;\n                }\n            }\n        }\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"ValueAdditionBatchQueueProcessor{\" +\n            \"value=\" + value +\n            \", sequence=\" + sequence +\n            \", count=\" + count +\n            '}';\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/ValueAdditionEventHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.util.PaddedLong;\n\nimport java.util.concurrent.CountDownLatch;\n\npublic final class ValueAdditionEventHandler implements EventHandler<ValueEvent>\n{\n    private final PaddedLong value = new PaddedLong();\n    private final PaddedLong batchesProcessed = new PaddedLong();\n    private long count;\n    private CountDownLatch latch;\n\n    public long getValue()\n    {\n        return value.get();\n    }\n\n    public long getBatchesProcessed()\n    {\n        return batchesProcessed.get();\n    }\n\n    public void reset(final CountDownLatch latch, final long expectedCount)\n    {\n        value.set(0L);\n        this.latch = latch;\n        count = expectedCount;\n        batchesProcessed.set(0);\n    }\n\n    @Override\n    public void onEvent(final ValueEvent event, final long sequence, final boolean endOfBatch) throws Exception\n    {\n        value.set(value.get() + event.getValue());\n\n        if (count == sequence)\n        {\n            latch.countDown();\n        }\n    }\n\n    @Override\n    public void onBatchStart(final long batchSize, final long queueDepth)\n    {\n        batchesProcessed.increment();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/ValueAdditionQueueBatchProcessor.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport java.util.ArrayList;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\n\npublic final class ValueAdditionQueueBatchProcessor implements Runnable\n{\n    private volatile boolean running;\n    private long value;\n    private long sequence;\n    private CountDownLatch latch;\n\n    private final BlockingQueue<Long> blockingQueue;\n    private final ArrayList<Long> buffer = new ArrayList<>();\n    private final long count;\n\n    public ValueAdditionQueueBatchProcessor(final BlockingQueue<Long> blockingQueue, final long count)\n    {\n        this.blockingQueue = blockingQueue;\n        this.count = count;\n    }\n\n    public long getValue()\n    {\n        return value;\n    }\n\n    public void reset(final CountDownLatch latch)\n    {\n        value = 0L;\n        sequence = 0L;\n        this.latch = latch;\n    }\n\n    public void halt()\n    {\n        running = false;\n    }\n\n    @Override\n    public void run()\n    {\n        running = true;\n        while (true)\n        {\n            try\n            {\n                blockingQueue.drainTo(buffer);\n                if (buffer.isEmpty())\n                {\n                    long value = blockingQueue.take().longValue();\n                    this.value += value;\n                    ++sequence;\n                }\n                else\n                {\n                    for (Long v : buffer)\n                    {\n                        this.value += v;\n                    }\n                    sequence += buffer.size();\n                    buffer.clear();\n                }\n\n                if (sequence >= count)\n                {\n                    latch.countDown();\n                }\n            }\n            catch (InterruptedException ex)\n            {\n                if (!running)\n                {\n                    break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/ValueAdditionQueueProcessor.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\n\npublic final class ValueAdditionQueueProcessor implements Runnable\n{\n    private volatile boolean running;\n    private long value;\n    private long sequence;\n    private CountDownLatch latch;\n\n    private final BlockingQueue<Long> blockingQueue;\n    private final long count;\n\n    public ValueAdditionQueueProcessor(final BlockingQueue<Long> blockingQueue, final long count)\n    {\n        this.blockingQueue = blockingQueue;\n        this.count = count;\n    }\n\n    public long getValue()\n    {\n        return value;\n    }\n\n    public void reset(final CountDownLatch latch)\n    {\n        value = 0L;\n        sequence = 0L;\n        this.latch = latch;\n    }\n\n    public void halt()\n    {\n        running = false;\n    }\n\n    @Override\n    public void run()\n    {\n        running = true;\n        while (true)\n        {\n            try\n            {\n                long value = blockingQueue.take().longValue();\n                this.value += value;\n\n                if (sequence++ == count)\n                {\n                    latch.countDown();\n                }\n            }\n            catch (InterruptedException ex)\n            {\n                if (!running)\n                {\n                    break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/ValueBatchPublisher.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.RingBuffer;\n\nimport java.util.concurrent.CyclicBarrier;\n\npublic final class ValueBatchPublisher implements Runnable\n{\n    private final CyclicBarrier cyclicBarrier;\n    private final RingBuffer<ValueEvent> ringBuffer;\n    private final long iterations;\n    private final int batchSize;\n\n    public ValueBatchPublisher(\n        final CyclicBarrier cyclicBarrier,\n        final RingBuffer<ValueEvent> ringBuffer,\n        final long iterations,\n        final int batchSize)\n    {\n        this.cyclicBarrier = cyclicBarrier;\n        this.ringBuffer = ringBuffer;\n        this.iterations = iterations;\n        this.batchSize = batchSize;\n    }\n\n    @Override\n    public void run()\n    {\n        try\n        {\n            cyclicBarrier.await();\n\n            for (long i = 0; i < iterations; i += batchSize)\n            {\n                long hi = ringBuffer.next(batchSize);\n                long lo = hi - (batchSize - 1);\n                for (long l = lo; l <= hi; l++)\n                {\n                    ValueEvent event = ringBuffer.get(l);\n                    event.setValue(l);\n                }\n                ringBuffer.publish(lo, hi);\n            }\n        }\n        catch (Exception ex)\n        {\n            throw new RuntimeException(ex);\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/ValueEvent.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventFactory;\n\npublic final class ValueEvent\n{\n    private long value;\n\n    public long getValue()\n    {\n        return value;\n    }\n\n    public void setValue(final long value)\n    {\n        this.value = value;\n    }\n\n    public static final EventFactory<ValueEvent> EVENT_FACTORY = ValueEvent::new;\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/ValueMutationEventHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.util.PaddedLong;\n\nimport java.util.concurrent.CountDownLatch;\n\npublic final class ValueMutationEventHandler implements EventHandler<ValueEvent>\n{\n    private final Operation operation;\n    private final PaddedLong value = new PaddedLong();\n    private final PaddedLong batchesProcessed = new PaddedLong();\n    private long count;\n    private CountDownLatch latch;\n\n    public ValueMutationEventHandler(final Operation operation)\n    {\n        this.operation = operation;\n    }\n\n    public long getValue()\n    {\n        return value.get();\n    }\n\n    public long getBatchesProcessed()\n    {\n        return batchesProcessed.get();\n    }\n\n    public void reset(final CountDownLatch latch, final long expectedCount)\n    {\n        value.set(0L);\n        this.latch = latch;\n        count = expectedCount;\n        batchesProcessed.set(0);\n    }\n\n    @Override\n    public void onEvent(final ValueEvent event, final long sequence, final boolean endOfBatch) throws Exception\n    {\n        value.set(operation.op(value.get(), event.getValue()));\n\n        if (count == sequence)\n        {\n            latch.countDown();\n        }\n    }\n\n    @Override\n    public void onBatchStart(final long batchSize, final long queueDepth)\n    {\n        batchesProcessed.increment();\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/ValueMutationQueueProcessor.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\n\npublic final class ValueMutationQueueProcessor implements Runnable\n{\n    private volatile boolean running;\n    private long value;\n    private long sequence;\n    private CountDownLatch latch;\n\n    private final BlockingQueue<Long> blockingQueue;\n    private final Operation operation;\n    private final long count;\n\n    public ValueMutationQueueProcessor(\n        final BlockingQueue<Long> blockingQueue, final Operation operation, final long count)\n    {\n        this.blockingQueue = blockingQueue;\n        this.operation = operation;\n        this.count = count;\n    }\n\n    public long getValue()\n    {\n        return value;\n    }\n\n    public void reset(final CountDownLatch latch)\n    {\n        value = 0L;\n        sequence = 0L;\n        this.latch = latch;\n    }\n\n    public void halt()\n    {\n        running = false;\n    }\n\n    @Override\n    public void run()\n    {\n        running = true;\n        while (true)\n        {\n            try\n            {\n                long value = blockingQueue.take().longValue();\n                this.value = operation.op(this.value, value);\n\n                if (sequence++ == count)\n                {\n                    latch.countDown();\n                }\n            }\n            catch (InterruptedException ex)\n            {\n                if (!running)\n                {\n                    break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/ValuePublisher.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.RingBuffer;\n\nimport java.util.concurrent.CyclicBarrier;\n\npublic final class ValuePublisher implements Runnable\n{\n    private final CyclicBarrier cyclicBarrier;\n    private final RingBuffer<ValueEvent> ringBuffer;\n    private final long iterations;\n\n    public ValuePublisher(\n        final CyclicBarrier cyclicBarrier, final RingBuffer<ValueEvent> ringBuffer, final long iterations)\n    {\n        this.cyclicBarrier = cyclicBarrier;\n        this.ringBuffer = ringBuffer;\n        this.iterations = iterations;\n    }\n\n    @Override\n    public void run()\n    {\n        try\n        {\n            cyclicBarrier.await();\n\n            for (long i = 0; i < iterations; i++)\n            {\n                long sequence = ringBuffer.next();\n                ValueEvent event = ringBuffer.get(sequence);\n                event.setValue(i);\n                ringBuffer.publish(sequence);\n            }\n        }\n        catch (Exception ex)\n        {\n            throw new RuntimeException(ex);\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/support/ValueQueuePublisher.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CyclicBarrier;\n\npublic final class ValueQueuePublisher implements Runnable\n{\n    private final CyclicBarrier cyclicBarrier;\n    private final BlockingQueue<Long> blockingQueue;\n    private final long iterations;\n\n    public ValueQueuePublisher(\n        final CyclicBarrier cyclicBarrier, final BlockingQueue<Long> blockingQueue, final long iterations)\n    {\n        this.cyclicBarrier = cyclicBarrier;\n        this.blockingQueue = blockingQueue;\n        this.iterations = iterations;\n    }\n\n    @Override\n    public void run()\n    {\n        try\n        {\n            cyclicBarrier.await();\n            for (long i = 0; i < iterations; i++)\n            {\n                blockingQueue.put(Long.valueOf(i));\n            }\n        }\n        catch (Exception ex)\n        {\n            throw new RuntimeException(ex);\n        }\n    }\n}\n"
  },
  {
    "path": "src/perftest/java/com/lmax/disruptor/translator/OneToOneTranslatorThroughputTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.translator;\n\nimport com.lmax.disruptor.AbstractPerfTestDisruptor;\nimport com.lmax.disruptor.EventTranslatorOneArg;\nimport com.lmax.disruptor.PerfTestContext;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.YieldingWaitStrategy;\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.dsl.ProducerType;\nimport com.lmax.disruptor.support.PerfTestUtil;\nimport com.lmax.disruptor.support.ValueAdditionEventHandler;\nimport com.lmax.disruptor.support.ValueEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport com.lmax.disruptor.util.MutableLong;\n\nimport java.util.concurrent.CountDownLatch;\n\nimport static com.lmax.disruptor.support.PerfTestUtil.failIfNot;\n\n/**\n * <pre>\n * UniCast a series of items between 1 publisher and 1 event processor using the EventTranslator API\n *\n * +----+    +-----+\n * | P1 |--->| EP1 |\n * +----+    +-----+\n *\n * Disruptor:\n * ==========\n *              track to prevent wrap\n *              +------------------+\n *              |                  |\n *              |                  v\n * +----+    +====+    +====+   +-----+\n * | P1 |--->| RB |<---| SB |   | EP1 |\n * +----+    +====+    +====+   +-----+\n *      claim      get    ^        |\n *                        |        |\n *                        +--------+\n *                          waitFor\n *\n * P1  - Publisher 1\n * RB  - RingBuffer\n * SB  - SequenceBarrier\n * EP1 - EventProcessor 1\n *\n * </pre>\n */\npublic final class OneToOneTranslatorThroughputTest extends AbstractPerfTestDisruptor\n{\n    private static final int BUFFER_SIZE = 1024 * 64;\n    private static final long ITERATIONS = 1000L * 1000L * 100L;\n    private final long expectedResult = PerfTestUtil.accumulatedAddition(ITERATIONS);\n    private final ValueAdditionEventHandler handler = new ValueAdditionEventHandler();\n    private final RingBuffer<ValueEvent> ringBuffer;\n    private final MutableLong value = new MutableLong(0);\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @SuppressWarnings(\"unchecked\")\n    public OneToOneTranslatorThroughputTest()\n    {\n        Disruptor<ValueEvent> disruptor =\n                new Disruptor<>(\n                        ValueEvent.EVENT_FACTORY,\n                        BUFFER_SIZE, DaemonThreadFactory.INSTANCE,\n                        ProducerType.SINGLE,\n                        new YieldingWaitStrategy());\n        disruptor.handleEventsWith(handler);\n        this.ringBuffer = disruptor.start();\n    }\n\n    ///////////////////////////////////////////////////////////////////////////////////////////////\n\n    @Override\n    protected int getRequiredProcessorCount()\n    {\n        return 2;\n    }\n\n    @Override\n    protected PerfTestContext runDisruptorPass() throws InterruptedException\n    {\n        PerfTestContext perfTestContext = new PerfTestContext();\n        MutableLong value = this.value;\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        long expectedCount = ringBuffer.getMinimumGatingSequence() + ITERATIONS;\n\n        handler.reset(latch, expectedCount);\n        long start = System.currentTimeMillis();\n\n        final RingBuffer<ValueEvent> rb = ringBuffer;\n\n        for (long l = 0; l < ITERATIONS; l++)\n        {\n            value.set(l);\n            rb.publishEvent(Translator.INSTANCE, value);\n        }\n\n        latch.await();\n        perfTestContext.setDisruptorOps((ITERATIONS * 1000L) / (System.currentTimeMillis() - start));\n        perfTestContext.setBatchData(handler.getBatchesProcessed(), ITERATIONS);\n        waitForEventProcessorSequence(expectedCount);\n\n        failIfNot(expectedResult, handler.getValue());\n\n        return perfTestContext;\n    }\n\n    private static class Translator implements EventTranslatorOneArg<ValueEvent, MutableLong>\n    {\n        private static final Translator INSTANCE = new Translator();\n\n        @Override\n        public void translateTo(final ValueEvent event, final long sequence, final MutableLong arg0)\n        {\n            event.setValue(arg0.get());\n        }\n    }\n\n    private void waitForEventProcessorSequence(final long expectedCount) throws InterruptedException\n    {\n        while (ringBuffer.getMinimumGatingSequence() != expectedCount)\n        {\n            Thread.sleep(1);\n        }\n    }\n\n    public static void main(final String[] args) throws Exception\n    {\n        OneToOneTranslatorThroughputTest test = new OneToOneTranslatorThroughputTest();\n        test.testImplementations();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/AggregateEventHandlerTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.DummyEventHandler;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.Is.is;\n\n@SuppressWarnings(\"unchecked\")\npublic final class AggregateEventHandlerTest\n{\n    private final DummyEventHandler<int[]> eh1 = new DummyEventHandler<>();\n    private final DummyEventHandler<int[]> eh2 = new DummyEventHandler<>();\n    private final DummyEventHandler<int[]> eh3 = new DummyEventHandler<>();\n\n    @Test\n    public void shouldCallOnEventInSequence()\n        throws Exception\n    {\n        final int[] event = {7};\n        final long sequence = 3L;\n        final boolean endOfBatch = true;\n\n        final AggregateEventHandler<int[]> aggregateEventHandler = new AggregateEventHandler<>(eh1, eh2, eh3);\n\n        aggregateEventHandler.onEvent(event, sequence, endOfBatch);\n        assertLastEvent(event, sequence, eh1, eh2, eh3);\n    }\n\n    @Test\n    public void shouldCallOnStartInSequence()\n        throws Exception\n    {\n        final AggregateEventHandler<int[]> aggregateEventHandler = new AggregateEventHandler<>(eh1, eh2, eh3);\n\n        aggregateEventHandler.onStart();\n\n        assertStartCalls(1, eh1, eh2, eh3);\n    }\n\n    @Test\n    public void shouldCallOnShutdownInSequence()\n        throws Exception\n    {\n        final AggregateEventHandler<int[]> aggregateEventHandler = new AggregateEventHandler<>(eh1, eh2, eh3);\n\n        aggregateEventHandler.onShutdown();\n\n        assertShutdownCalls(1, eh1, eh2, eh3);\n    }\n\n    @Test\n    public void shouldHandleEmptyListOfEventHandlers() throws Exception\n    {\n        final AggregateEventHandler<int[]> aggregateEventHandler = new AggregateEventHandler<>();\n\n        aggregateEventHandler.onEvent(new int[]{7}, 0L, true);\n        aggregateEventHandler.onStart();\n        aggregateEventHandler.onShutdown();\n    }\n\n    private static void assertLastEvent(final int[] event, final long sequence, final DummyEventHandler<int[]>... eh1)\n    {\n        for (DummyEventHandler<int[]> eh : eh1)\n        {\n            assertThat(eh.lastEvent, is(event));\n            assertThat(eh.lastSequence, is(sequence));\n        }\n    }\n\n    private static void assertStartCalls(final int startCalls, final DummyEventHandler<int[]>... handlers)\n    {\n        for (DummyEventHandler<int[]> handler : handlers)\n        {\n            assertThat(handler.startCalls, is(startCalls));\n        }\n    }\n\n    private static void assertShutdownCalls(final int startCalls, final DummyEventHandler<int[]>... handlers)\n    {\n        for (DummyEventHandler<int[]> handler : handlers)\n        {\n            assertThat(handler.shutdownCalls, is(startCalls));\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/BatchEventProcessorTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.StubEvent;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static com.lmax.disruptor.RingBuffer.createMultiProducer;\nimport static org.hamcrest.CoreMatchers.not;\nimport static org.hamcrest.CoreMatchers.nullValue;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\npublic final class BatchEventProcessorTest\n{\n    private final RingBuffer<StubEvent> ringBuffer = createMultiProducer(StubEvent.EVENT_FACTORY, 16);\n    private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n\n    @Test\n    public void shouldThrowExceptionOnSettingNullExceptionHandler()\n    {\n        assertThrows(NullPointerException.class, () ->\n        {\n            final BatchEventProcessor<StubEvent> batchEventProcessor = new BatchEventProcessorBuilder().build(\n                    ringBuffer, sequenceBarrier, new ExceptionEventHandler());\n            batchEventProcessor.setExceptionHandler(null);\n        });\n    }\n\n    @Test\n    public void shouldCallMethodsInLifecycleOrderForBatch()\n        throws Exception\n    {\n        CountDownLatch eventLatch = new CountDownLatch(3);\n        LatchEventHandler eventHandler = new LatchEventHandler(eventLatch);\n        final BatchEventProcessor<StubEvent> batchEventProcessor = new BatchEventProcessorBuilder().build(\n                ringBuffer, sequenceBarrier, eventHandler);\n\n        ringBuffer.addGatingSequences(batchEventProcessor.getSequence());\n\n        ringBuffer.publish(ringBuffer.next());\n        ringBuffer.publish(ringBuffer.next());\n        ringBuffer.publish(ringBuffer.next());\n\n        Thread thread = new Thread(batchEventProcessor);\n        thread.start();\n\n        assertTrue(eventLatch.await(2, TimeUnit.SECONDS));\n\n        batchEventProcessor.halt();\n        thread.join();\n    }\n\n    @Test\n    public void shouldCallExceptionHandlerOnUncaughtException()\n        throws Exception\n    {\n        CountDownLatch exceptionLatch = new CountDownLatch(1);\n        LatchExceptionHandler latchExceptionHandler = new LatchExceptionHandler(exceptionLatch);\n        final BatchEventProcessor<StubEvent> batchEventProcessor = new BatchEventProcessorBuilder().build(\n                ringBuffer, sequenceBarrier, new ExceptionEventHandler());\n        ringBuffer.addGatingSequences(batchEventProcessor.getSequence());\n\n        batchEventProcessor.setExceptionHandler(latchExceptionHandler);\n\n        Thread thread = new Thread(batchEventProcessor);\n        thread.start();\n\n        ringBuffer.publish(ringBuffer.next());\n\n        assertTrue(exceptionLatch.await(2, TimeUnit.SECONDS));\n\n        batchEventProcessor.halt();\n        thread.join();\n    }\n\n    private static class LatchEventHandler implements EventHandler<StubEvent>\n    {\n        private final CountDownLatch latch;\n\n        LatchEventHandler(final CountDownLatch latch)\n        {\n            this.latch = latch;\n        }\n\n        @Override\n        public void onEvent(final StubEvent event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            latch.countDown();\n        }\n    }\n\n    private static class LatchExceptionHandler implements ExceptionHandler<StubEvent>\n    {\n        private final CountDownLatch latch;\n\n        LatchExceptionHandler(final CountDownLatch latch)\n        {\n            this.latch = latch;\n        }\n\n        @Override\n        public void handleEventException(final Throwable ex, final long sequence, final StubEvent event)\n        {\n            latch.countDown();\n        }\n\n        @Override\n        public void handleOnStartException(final Throwable ex)\n        {\n\n        }\n\n        @Override\n        public void handleOnShutdownException(final Throwable ex)\n        {\n\n        }\n    }\n\n    private static class ExceptionEventHandler implements EventHandler<StubEvent>\n    {\n        @Override\n        public void onEvent(final StubEvent event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            throw new NullPointerException(null);\n        }\n    }\n\n    @Test\n    public void reportAccurateBatchSizesAtBatchStartTime()\n        throws Exception\n    {\n        final List<Long> batchSizes = new ArrayList<>();\n        final CountDownLatch eventLatch = new CountDownLatch(6);\n\n        final class LoopbackEventHandler\n            implements EventHandler<StubEvent>\n        {\n\n            @Override\n            public void onBatchStart(final long batchSize, final long queueDepth)\n            {\n                batchSizes.add(batchSize);\n            }\n\n            @Override\n            public void onEvent(final StubEvent event, final long sequence, final boolean endOfBatch)\n                throws Exception\n            {\n                if (!endOfBatch)\n                {\n                    ringBuffer.publish(ringBuffer.next());\n                }\n                eventLatch.countDown();\n            }\n        }\n\n        final BatchEventProcessor<StubEvent> batchEventProcessor =\n                new BatchEventProcessorBuilder().build(\n                        ringBuffer, sequenceBarrier, new LoopbackEventHandler());\n\n        ringBuffer.publish(ringBuffer.next());\n        ringBuffer.publish(ringBuffer.next());\n        ringBuffer.publish(ringBuffer.next());\n\n        Thread thread = new Thread(batchEventProcessor);\n        thread.start();\n        eventLatch.await();\n\n        batchEventProcessor.halt();\n        thread.join();\n\n        assertEquals(Arrays.asList(3L, 2L, 1L), batchSizes);\n    }\n\n    @Test\n    public void shouldAlwaysHalt() throws InterruptedException\n    {\n        WaitStrategy waitStrategy = new BusySpinWaitStrategy();\n        final SingleProducerSequencer sequencer = new SingleProducerSequencer(8, waitStrategy);\n        final ProcessingSequenceBarrier barrier = new ProcessingSequenceBarrier(\n            sequencer, waitStrategy, new Sequence(-1), new Sequence[0]);\n        DataProvider<Object> dp = sequence -> null;\n\n        final LatchLifeCycleHandler h1 = new LatchLifeCycleHandler();\n        final BatchEventProcessor p1 = new BatchEventProcessorBuilder().build(dp, barrier, h1);\n\n        Thread t1 = new Thread(p1);\n        p1.halt();\n        t1.start();\n\n        assertTrue(h1.awaitStart(2, TimeUnit.SECONDS));\n        assertTrue(h1.awaitStop(2, TimeUnit.SECONDS));\n\n        for (int i = 0; i < 1000; i++)\n        {\n            final LatchLifeCycleHandler h2 = new LatchLifeCycleHandler();\n            final BatchEventProcessor p2 = new BatchEventProcessorBuilder().build(dp, barrier, h2);\n            Thread t2 = new Thread(p2);\n            t2.start();\n            p2.halt();\n\n            assertTrue(h2.awaitStart(2, TimeUnit.SECONDS));\n            assertTrue(h2.awaitStop(2, TimeUnit.SECONDS));\n        }\n\n        for (int i = 0; i < 1000; i++)\n        {\n            final LatchLifeCycleHandler h2 = new LatchLifeCycleHandler();\n            final BatchEventProcessor p2 = new BatchEventProcessorBuilder().build(dp, barrier, h2);\n            Thread t2 = new Thread(p2);\n            t2.start();\n            Thread.yield();\n            p2.halt();\n\n            assertTrue(h2.awaitStart(2, TimeUnit.SECONDS));\n            assertTrue(h2.awaitStop(2, TimeUnit.SECONDS));\n        }\n    }\n\n    private static class LatchLifeCycleHandler implements EventHandler<Object>\n    {\n        private final CountDownLatch startLatch = new CountDownLatch(1);\n        private final CountDownLatch stopLatch = new CountDownLatch(1);\n\n        @Override\n        public void onEvent(final Object event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n\n        }\n\n        @Override\n        public void onStart()\n        {\n            startLatch.countDown();\n        }\n\n        @Override\n        public void onShutdown()\n        {\n            stopLatch.countDown();\n        }\n\n        public boolean awaitStart(final long time, final TimeUnit unit) throws InterruptedException\n        {\n            return startLatch.await(time, unit);\n        }\n\n\n        public boolean awaitStop(final long time, final TimeUnit unit) throws InterruptedException\n        {\n            return stopLatch.await(time, unit);\n        }\n    }\n\n    @Test\n    public void shouldNotPassZeroSizeToBatchStartAware() throws Exception\n    {\n        BatchAwareEventHandler eventHandler = new BatchAwareEventHandler();\n\n        final BatchEventProcessor<StubEvent> batchEventProcessor = new BatchEventProcessorBuilder().build(\n                ringBuffer, new DelegatingSequenceBarrier(this.sequenceBarrier), eventHandler);\n\n        ringBuffer.addGatingSequences(batchEventProcessor.getSequence());\n\n        Thread thread = new Thread(batchEventProcessor);\n        thread.start();\n\n        for (int i = 0; i < 3; i++)\n        {\n            final long sequence = ringBuffer.next();\n            Thread.sleep(100);\n\n            ringBuffer.publish(sequence);\n        }\n\n        batchEventProcessor.halt();\n        thread.join();\n\n        assertThat(eventHandler.batchSizeToCountMap.size(), not(0));\n        assertThat(eventHandler.batchSizeToCountMap.get(0L), nullValue());\n    }\n\n    private static class DelegatingSequenceBarrier implements SequenceBarrier\n    {\n        private SequenceBarrier delegate;\n        private boolean suppress = true;\n\n        DelegatingSequenceBarrier(final SequenceBarrier delegate)\n        {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public long waitFor(final long sequence) throws AlertException, InterruptedException, TimeoutException\n        {\n            long result = suppress ? sequence - 1 : delegate.waitFor(sequence);\n            suppress = !suppress;\n            return result;\n        }\n\n        @Override\n        public long getCursor()\n        {\n            return delegate.getCursor();\n        }\n\n        @Override\n        public boolean isAlerted()\n        {\n            return delegate.isAlerted();\n        }\n\n        @Override\n        public void alert()\n        {\n            delegate.alert();\n        }\n\n        @Override\n        public void clearAlert()\n        {\n            delegate.clearAlert();\n        }\n\n        @Override\n        public void checkAlert() throws AlertException\n        {\n            delegate.checkAlert();\n        }\n    }\n\n    private static class BatchAwareEventHandler implements EventHandler<StubEvent>\n    {\n        final Map<Long, Integer> batchSizeToCountMap = new HashMap<>();\n\n        @Override\n        public void onEvent(final StubEvent event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n        }\n\n        @Override\n        public void onBatchStart(final long batchSize, final long queueDepth)\n        {\n            final Integer currentCount = batchSizeToCountMap.get(batchSize);\n            final int nextCount = null == currentCount ? 1 : currentCount + 1;\n            batchSizeToCountMap.put(batchSize, nextCount);\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/BatchingTest.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.dsl.ProducerType;\nimport com.lmax.disruptor.support.LongEvent;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport org.hamcrest.CoreMatchers;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport java.util.concurrent.locks.LockSupport;\nimport java.util.stream.Stream;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.params.provider.Arguments.arguments;\n\npublic class BatchingTest\n{\n    public static Stream<Arguments> generateData()\n    {\n        return Stream.of(arguments(ProducerType.MULTI), arguments(ProducerType.SINGLE));\n    }\n\n    private static class ParallelEventHandler implements EventHandler<LongEvent>\n    {\n        private final long mask;\n        private final long ordinal;\n        private final int batchSize = 10;\n\n        private long eventCount;\n        private long batchCount;\n        private long publishedValue;\n        private long tempValue;\n        private volatile long processed;\n\n        ParallelEventHandler(final long mask, final long ordinal)\n        {\n            this.mask = mask;\n            this.ordinal = ordinal;\n        }\n\n        @Override\n        public void onEvent(final LongEvent event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            if ((sequence & mask) == ordinal)\n            {\n                eventCount++;\n                tempValue = event.get();\n            }\n\n            if (endOfBatch || ++batchCount >= batchSize)\n            {\n                publishedValue = tempValue;\n                batchCount = 0;\n            }\n            else\n            {\n                LockSupport.parkNanos(1);\n            }\n\n            processed = sequence;\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @ParameterizedTest\n    @MethodSource(\"generateData\")\n    public void shouldBatch(final ProducerType producerType) throws Exception\n    {\n        Disruptor<LongEvent> d = new Disruptor<>(\n                LongEvent.FACTORY, 2048, DaemonThreadFactory.INSTANCE,\n                producerType, new SleepingWaitStrategy());\n\n        ParallelEventHandler handler1 = new ParallelEventHandler(1, 0);\n        ParallelEventHandler handler2 = new ParallelEventHandler(1, 1);\n\n        d.handleEventsWith(handler1, handler2);\n\n        RingBuffer<LongEvent> buffer = d.start();\n\n        EventTranslator<LongEvent> translator = (event, sequence) -> event.set(sequence);\n\n        int eventCount = 10000;\n        for (int i = 0; i < eventCount; i++)\n        {\n            buffer.publishEvent(translator);\n        }\n\n        while (handler1.processed != eventCount - 1 ||\n            handler2.processed != eventCount - 1)\n        {\n            Thread.sleep(1);\n        }\n\n        assertThat(handler1.publishedValue, CoreMatchers.is((long) eventCount - 2));\n        assertThat(handler1.eventCount, CoreMatchers.is((long) eventCount / 2));\n        assertThat(handler2.publishedValue, CoreMatchers.is((long) eventCount - 1));\n        assertThat(handler2.eventCount, CoreMatchers.is((long) eventCount / 2));\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/BusySpinWaitStrategyTest.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport org.junit.jupiter.api.Test;\n\nimport static com.lmax.disruptor.support.WaitStrategyTestUtil.assertWaitForWithDelayOf;\n\npublic class BusySpinWaitStrategyTest\n{\n\n    @Test\n    public void shouldWaitForValue() throws Exception\n    {\n        assertWaitForWithDelayOf(50, new BusySpinWaitStrategy());\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/DisruptorStressTest.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.dsl.ProducerType;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.locks.LockSupport;\n\nimport static java.lang.Math.max;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.not;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\npublic class DisruptorStressTest\n{\n    private final ExecutorService executor = Executors.newCachedThreadPool();\n\n    @Test\n    public void shouldHandleLotsOfThreads() throws Exception\n    {\n        Disruptor<TestEvent> disruptor = new Disruptor<>(\n                TestEvent.FACTORY, 1 << 16, DaemonThreadFactory.INSTANCE,\n                ProducerType.MULTI, new BusySpinWaitStrategy());\n        RingBuffer<TestEvent> ringBuffer = disruptor.getRingBuffer();\n        disruptor.setDefaultExceptionHandler(new FatalExceptionHandler());\n\n        int threads = max(1, Runtime.getRuntime().availableProcessors() / 2);\n\n        int iterations = 200000;\n        int publisherCount = threads;\n        int handlerCount = threads;\n\n        CyclicBarrier barrier = new CyclicBarrier(publisherCount);\n        CountDownLatch latch = new CountDownLatch(publisherCount);\n\n        TestEventHandler[] handlers = initialise(disruptor, new TestEventHandler[handlerCount]);\n        Publisher[] publishers = initialise(new Publisher[publisherCount], ringBuffer, iterations, barrier, latch);\n\n        disruptor.start();\n\n        for (Publisher publisher : publishers)\n        {\n            executor.execute(publisher);\n        }\n\n        latch.await();\n        while (ringBuffer.getCursor() < (iterations - 1))\n        {\n            LockSupport.parkNanos(1);\n        }\n\n        disruptor.shutdown();\n\n        for (Publisher publisher : publishers)\n        {\n            assertThat(publisher.failed, is(false));\n        }\n\n        for (TestEventHandler handler : handlers)\n        {\n            assertThat(handler.messagesSeen, is(not(0)));\n            assertThat(handler.failureCount, is(0));\n        }\n    }\n\n    private Publisher[] initialise(\n            final Publisher[] publishers, final RingBuffer<TestEvent> buffer,\n            final int messageCount, final CyclicBarrier barrier, final CountDownLatch latch)\n    {\n        for (int i = 0; i < publishers.length; i++)\n        {\n            publishers[i] = new Publisher(buffer, messageCount, barrier, latch);\n        }\n\n        return publishers;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private TestEventHandler[] initialise(final Disruptor<TestEvent> disruptor, final TestEventHandler[] testEventHandlers)\n    {\n        for (int i = 0; i < testEventHandlers.length; i++)\n        {\n            TestEventHandler handler = new TestEventHandler();\n            disruptor.handleEventsWith(handler);\n            testEventHandlers[i] = handler;\n        }\n\n        return testEventHandlers;\n    }\n\n    private static class TestEventHandler implements EventHandler<TestEvent>\n    {\n        public int failureCount = 0;\n        public int messagesSeen = 0;\n\n        TestEventHandler()\n        {\n        }\n\n        @Override\n        public void onEvent(final TestEvent event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            if (event.sequence != sequence ||\n                event.a != sequence + 13 ||\n                event.b != sequence - 7 ||\n                !(\"wibble-\" + sequence).equals(event.s))\n            {\n                failureCount++;\n            }\n\n            messagesSeen++;\n        }\n    }\n\n    private static class Publisher implements Runnable\n    {\n        private final RingBuffer<TestEvent> ringBuffer;\n        private final CyclicBarrier barrier;\n        private final int iterations;\n        private final CountDownLatch shutdownLatch;\n\n        public boolean failed = false;\n\n        Publisher(\n            final RingBuffer<TestEvent> ringBuffer,\n            final int iterations,\n            final CyclicBarrier barrier,\n            final CountDownLatch shutdownLatch)\n        {\n            this.ringBuffer = ringBuffer;\n            this.barrier = barrier;\n            this.iterations = iterations;\n            this.shutdownLatch = shutdownLatch;\n        }\n\n        @Override\n        public void run()\n        {\n            try\n            {\n                barrier.await();\n\n                int i = iterations;\n                while (--i != -1)\n                {\n                    long next = ringBuffer.next();\n                    TestEvent testEvent = ringBuffer.get(next);\n                    testEvent.sequence = next;\n                    testEvent.a = next + 13;\n                    testEvent.b = next - 7;\n                    testEvent.s = \"wibble-\" + next;\n                    ringBuffer.publish(next);\n                }\n            }\n            catch (Exception e)\n            {\n                failed = true;\n            }\n            finally\n            {\n                shutdownLatch.countDown();\n            }\n        }\n    }\n\n    private static class TestEvent\n    {\n        public long sequence;\n        public long a;\n        public long b;\n        public String s;\n\n        public static final EventFactory<TestEvent> FACTORY = () -> new TestEvent();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/EventPollerTest.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.EventPoller.PollState;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.ArrayList;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.Is.is;\n\npublic class EventPollerTest\n{\n    @Test\n    @SuppressWarnings(\"unchecked\")\n    public void shouldPollForEvents() throws Exception\n    {\n        final Sequence gatingSequence = new Sequence();\n        final SingleProducerSequencer sequencer = new SingleProducerSequencer(16, new BusySpinWaitStrategy());\n        final EventPoller.Handler<Object> handler = (event, sequence, endOfBatch) -> false;\n\n        final Object[] data = new Object[16];\n        final DataProvider<Object> provider = sequence -> data[(int) sequence];\n\n        final EventPoller<Object> poller = sequencer.newPoller(provider, gatingSequence);\n        final Object event = new Object();\n        data[0] = event;\n\n        assertThat(poller.poll(handler), is(PollState.IDLE));\n\n        // Publish Event.\n        sequencer.publish(sequencer.next());\n        assertThat(poller.poll(handler), is(PollState.GATING));\n\n        gatingSequence.incrementAndGet();\n        assertThat(poller.poll(handler), is(PollState.PROCESSING));\n    }\n\n    @Test\n    public void shouldSuccessfullyPollWhenBufferIsFull() throws Exception\n    {\n        final ArrayList<byte[]> events = new ArrayList<>();\n\n        final EventPoller.Handler<byte[]> handler = (event, sequence, endOfBatch) ->\n        {\n            events.add(event);\n            return !endOfBatch;\n        };\n\n        EventFactory<byte[]> factory = () -> new byte[1];\n\n        final RingBuffer<byte[]> ringBuffer = RingBuffer.createMultiProducer(factory, 4, new SleepingWaitStrategy());\n\n        final EventPoller<byte[]> poller = ringBuffer.newPoller();\n        ringBuffer.addGatingSequences(poller.getSequence());\n\n        int count = 4;\n\n        for (byte i = 1; i <= count; ++i)\n        {\n            long next = ringBuffer.next();\n            ringBuffer.get(next)[0] = i;\n            ringBuffer.publish(next);\n        }\n\n        // think of another thread\n        poller.poll(handler);\n\n        assertThat(events.size(), is(4));\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/EventPublisherTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.LongEvent;\nimport org.junit.jupiter.api.Test;\n\nimport static com.lmax.disruptor.RingBuffer.createMultiProducer;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\npublic class EventPublisherTest implements EventTranslator<LongEvent>\n{\n    private static final int BUFFER_SIZE = 32;\n    private RingBuffer<LongEvent> ringBuffer = createMultiProducer(LongEvent.FACTORY, BUFFER_SIZE);\n\n    @Test\n    public void shouldPublishEvent()\n    {\n        ringBuffer.addGatingSequences(new NoOpEventProcessor(ringBuffer).getSequence());\n\n        ringBuffer.publishEvent(this);\n        ringBuffer.publishEvent(this);\n\n        assertThat(Long.valueOf(ringBuffer.get(0).get()), is(Long.valueOf(0 + 29L)));\n        assertThat(Long.valueOf(ringBuffer.get(1).get()), is(Long.valueOf(1 + 29L)));\n    }\n\n    @Test\n    public void shouldTryPublishEvent() throws Exception\n    {\n        ringBuffer.addGatingSequences(new Sequence());\n\n        for (int i = 0; i < BUFFER_SIZE; i++)\n        {\n            assertThat(ringBuffer.tryPublishEvent(this), is(true));\n        }\n\n        for (int i = 0; i < BUFFER_SIZE; i++)\n        {\n            assertThat(Long.valueOf(ringBuffer.get(i).get()), is(Long.valueOf(i + 29L)));\n        }\n\n        assertThat(ringBuffer.tryPublishEvent(this), is(false));\n    }\n\n    @Override\n    public void translateTo(final LongEvent event, final long sequence)\n    {\n        event.set(sequence + 29);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/EventTranslatorTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.StubEvent;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\npublic final class EventTranslatorTest\n{\n    private static final String TEST_VALUE = \"Wibble\";\n\n    @Test\n    public void shouldTranslateOtherDataIntoAnEvent()\n    {\n        StubEvent event = StubEvent.EVENT_FACTORY.newInstance();\n        EventTranslator<StubEvent> eventTranslator = new ExampleEventTranslator(TEST_VALUE);\n\n        eventTranslator.translateTo(event, 0);\n\n        assertEquals(TEST_VALUE, event.getTestString());\n    }\n\n    public static final class ExampleEventTranslator\n        implements EventTranslator<StubEvent>\n    {\n        private final String testValue;\n\n        public ExampleEventTranslator(final String testValue)\n        {\n            this.testValue = testValue;\n        }\n\n        @Override\n        public void translateTo(final StubEvent event, final long sequence)\n        {\n            event.setTestString(testValue);\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/FatalExceptionHandlerTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.TestEvent;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\npublic final class FatalExceptionHandlerTest\n{\n    @Test\n    public void shouldHandleFatalException()\n    {\n        final Exception causeException = new Exception();\n        final TestEvent event = new TestEvent();\n\n        ExceptionHandler<Object> exceptionHandler = new FatalExceptionHandler();\n\n        Throwable ex =  assertThrows(RuntimeException.class, () -> exceptionHandler.handleEventException(causeException, 0L, event));\n\n        assertEquals(causeException, ex.getCause());\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/FixedSequenceGroupTest.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n\npublic class FixedSequenceGroupTest\n{\n\n    @Test\n    public void shouldReturnMinimumOf2Sequences() throws Exception\n    {\n        Sequence sequence1 = new Sequence(34);\n        Sequence sequnece2 = new Sequence(47);\n        Sequence group = new FixedSequenceGroup(new Sequence[]{sequence1, sequnece2});\n\n        assertThat(group.get(), is(34L));\n        sequence1.set(35);\n        assertThat(group.get(), is(35L));\n        sequence1.set(48);\n        assertThat(group.get(), is(47L));\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/IgnoreExceptionHandlerTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.TestEvent;\nimport org.junit.jupiter.api.Test;\n\npublic final class IgnoreExceptionHandlerTest\n{\n    @Test\n    public void shouldHandleAndIgnoreException()\n    {\n        final Exception ex = new Exception();\n        final TestEvent event = new TestEvent();\n\n        ExceptionHandler<Object> exceptionHandler = new IgnoreExceptionHandler();\n        exceptionHandler.handleEventException(ex, 0L, event);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/LifecycleAwareTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.StubEvent;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.CountDownLatch;\n\nimport static com.lmax.disruptor.RingBuffer.createMultiProducer;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.Is.is;\n\npublic final class LifecycleAwareTest\n{\n    private final CountDownLatch startLatch = new CountDownLatch(1);\n    private final CountDownLatch shutdownLatch = new CountDownLatch(1);\n\n\n    private final RingBuffer<StubEvent> ringBuffer = createMultiProducer(StubEvent.EVENT_FACTORY, 16);\n    private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n    private final LifecycleAwareEventHandler handler = new LifecycleAwareEventHandler();\n    private final BatchEventProcessor<StubEvent> batchEventProcessor =\n            new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, handler);\n\n    @Test\n    public void shouldNotifyOfBatchProcessorLifecycle() throws Exception\n    {\n        new Thread(batchEventProcessor).start();\n\n        startLatch.await();\n        batchEventProcessor.halt();\n\n        shutdownLatch.await();\n\n        assertThat(Integer.valueOf(handler.startCounter), is(Integer.valueOf(1)));\n        assertThat(Integer.valueOf(handler.shutdownCounter), is(Integer.valueOf(1)));\n    }\n\n    private final class LifecycleAwareEventHandler implements EventHandler<StubEvent>\n    {\n        private int startCounter = 0;\n        private int shutdownCounter = 0;\n\n        @Override\n        public void onEvent(final StubEvent event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n        }\n\n        @Override\n        public void onStart()\n        {\n            ++startCounter;\n            startLatch.countDown();\n        }\n\n        @Override\n        public void onShutdown()\n        {\n            ++shutdownCounter;\n            shutdownLatch.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/LiteTimeoutBlockingWaitStrategyTest.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.DummySequenceBarrier;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\npublic class LiteTimeoutBlockingWaitStrategyTest\n{\n    @Test\n    public void shouldTimeoutWaitFor()\n    {\n        final SequenceBarrier sequenceBarrier = new DummySequenceBarrier();\n\n        long theTimeout = 500;\n        LiteTimeoutBlockingWaitStrategy waitStrategy = new LiteTimeoutBlockingWaitStrategy(theTimeout, TimeUnit.MILLISECONDS);\n        Sequence cursor = new Sequence(5);\n\n        long t0 = System.currentTimeMillis();\n\n        assertThrows(TimeoutException.class, () -> waitStrategy.waitFor(6, cursor, cursor, sequenceBarrier));\n\n        long t1 = System.currentTimeMillis();\n\n        long timeWaiting = t1 - t0;\n\n        assertTrue(timeWaiting >= theTimeout);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/MaxBatchSizeEventProcessorTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.StubEvent;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\n\nimport static com.lmax.disruptor.RingBuffer.createSingleProducer;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\npublic final class MaxBatchSizeEventProcessorTest\n{\n    public static final int MAX_BATCH_SIZE = 3;\n    public static final int PUBLISH_COUNT = 5;\n    private final RingBuffer<StubEvent> ringBuffer = createSingleProducer(StubEvent.EVENT_FACTORY, 16);\n    private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n    private CountDownLatch countDownLatch;\n    private BatchEventProcessor<StubEvent> batchEventProcessor;\n    private Thread thread;\n    private BatchLimitRecordingHandler eventHandler;\n\n    @BeforeEach\n    void setUp()\n    {\n        countDownLatch = new CountDownLatch(PUBLISH_COUNT);\n        eventHandler = new BatchLimitRecordingHandler(countDownLatch);\n\n        batchEventProcessor = new BatchEventProcessorBuilder()\n                .setMaxBatchSize(MAX_BATCH_SIZE)\n                .build(ringBuffer, this.sequenceBarrier, eventHandler);\n\n        ringBuffer.addGatingSequences(batchEventProcessor.getSequence());\n\n        thread = new Thread(batchEventProcessor);\n        thread.start();\n    }\n\n    @Test\n    public void shouldLimitTheBatchToConfiguredMaxBatchSize() throws Exception\n    {\n        publishEvents();\n\n        assertEquals(eventHandler.batchedSequences, Arrays.asList(Arrays.asList(0L, 1L, 2L), Arrays.asList(3L, 4L)));\n    }\n\n    @Test\n    public void shouldAnnounceBatchSizeAndQueueDepthAtTheStartOfBatch() throws Exception\n    {\n        publishEvents();\n\n        assertEquals(eventHandler.announcedBatchSizes, Arrays.asList(3L, 2L));\n        assertEquals(eventHandler.announcedQueueDepths, Arrays.asList(5L, 2L));\n    }\n\n    @AfterEach\n    void tearDown() throws InterruptedException\n    {\n        batchEventProcessor.halt();\n        thread.join();\n    }\n\n    private void publishEvents() throws InterruptedException\n    {\n        long sequence = 0;\n        for (int i = 0; i < PUBLISH_COUNT; i++)\n        {\n            sequence = ringBuffer.next();\n        }\n        ringBuffer.publish(sequence);\n\n        //Wait for consumer to process all events\n        countDownLatch.await();\n    }\n\n    private static class BatchLimitRecordingHandler implements EventHandler<StubEvent>\n    {\n        public final List<List<Long>> batchedSequences = new ArrayList<>();\n        private List<Long> currentSequences;\n        private final CountDownLatch countDownLatch;\n        private final List<Long> announcedBatchSizes = new ArrayList<>();\n        private final List<Long> announcedQueueDepths = new ArrayList<>();\n\n        BatchLimitRecordingHandler(final CountDownLatch countDownLatch)\n        {\n            this.countDownLatch = countDownLatch;\n        }\n\n        @Override\n        public void onEvent(final StubEvent event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            currentSequences.add(sequence);\n            if (endOfBatch)\n            {\n                batchedSequences.add(currentSequences);\n                currentSequences = null;\n            }\n\n            countDownLatch.countDown();\n        }\n\n        @Override\n        public void onBatchStart(final long batchSize, final long queueDepth)\n        {\n            currentSequences = new ArrayList<>();\n            announcedBatchSizes.add(batchSize);\n            announcedQueueDepths.add(queueDepth);\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/MultiProducerSequencerTest.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\npublic class MultiProducerSequencerTest\n{\n    private final Sequencer publisher = new MultiProducerSequencer(1024, new BlockingWaitStrategy());\n\n    @Test\n    public void shouldOnlyAllowMessagesToBeAvailableIfSpecificallyPublished() throws Exception\n    {\n        publisher.publish(3);\n        publisher.publish(5);\n\n        assertThat(publisher.isAvailable(0), is(false));\n        assertThat(publisher.isAvailable(1), is(false));\n        assertThat(publisher.isAvailable(2), is(false));\n        assertThat(publisher.isAvailable(3), is(true));\n        assertThat(publisher.isAvailable(4), is(false));\n        assertThat(publisher.isAvailable(5), is(true));\n        assertThat(publisher.isAvailable(6), is(false));\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/PhasedBackoffWaitStrategyTest.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport org.junit.jupiter.api.Test;\n\nimport static com.lmax.disruptor.support.WaitStrategyTestUtil.assertWaitForWithDelayOf;\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\n\n\npublic class PhasedBackoffWaitStrategyTest\n{\n    @Test\n    public void shouldHandleImmediateSequenceChange() throws Exception\n    {\n        assertWaitForWithDelayOf(0, PhasedBackoffWaitStrategy.withLock(1, 1, MILLISECONDS));\n        assertWaitForWithDelayOf(0, PhasedBackoffWaitStrategy.withSleep(1, 1, MILLISECONDS));\n    }\n\n    @Test\n    public void shouldHandleSequenceChangeWithOneMillisecondDelay() throws Exception\n    {\n        assertWaitForWithDelayOf(1, PhasedBackoffWaitStrategy.withLock(1, 1, MILLISECONDS));\n        assertWaitForWithDelayOf(1, PhasedBackoffWaitStrategy.withSleep(1, 1, MILLISECONDS));\n    }\n\n    @Test\n    public void shouldHandleSequenceChangeWithTwoMillisecondDelay() throws Exception\n    {\n        assertWaitForWithDelayOf(2, PhasedBackoffWaitStrategy.withLock(1, 1, MILLISECONDS));\n        assertWaitForWithDelayOf(2, PhasedBackoffWaitStrategy.withSleep(1, 1, MILLISECONDS));\n    }\n\n    @Test\n    public void shouldHandleSequenceChangeWithTenMillisecondDelay() throws Exception\n    {\n        assertWaitForWithDelayOf(10, PhasedBackoffWaitStrategy.withLock(1, 1, MILLISECONDS));\n        assertWaitForWithDelayOf(10, PhasedBackoffWaitStrategy.withSleep(1, 1, MILLISECONDS));\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/RewindBatchEventProcessorTest.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.dsl.stubs.StubExceptionHandler;\nimport com.lmax.disruptor.support.LongEvent;\nimport org.hamcrest.Description;\nimport org.hamcrest.Matcher;\nimport org.hamcrest.TypeSafeMatcher;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static java.util.Arrays.asList;\nimport static java.util.Collections.emptyList;\nimport static java.util.Collections.singletonList;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\npublic class RewindBatchEventProcessorTest\n{\n    private static final int BUFFER_SIZE = 2048;\n    private RingBuffer<LongEvent> ringBuffer;\n    private final List<EventResult> values = new ArrayList<>();\n\n    @BeforeEach\n    public void setUp()\n    {\n        ringBuffer = RingBuffer.createMultiProducer(LongEvent.FACTORY, BUFFER_SIZE);\n    }\n\n    @Test\n    public void shouldRewindOnFirstEventOfBatchSizeOfOne()\n    {\n        fill(ringBuffer, 1);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values, List.of(rewind(0, 1)), 0, -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(event(0, 0)));\n    }\n\n\n    @Test\n    public void shouldRewindOnFirstEventOfBatch()\n    {\n        int ringBufferEntries = 10;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(\n                values,\n                singletonList(rewind(0, 1)),\n                lastSequenceNumber,\n                -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, lastSequenceNumber)));\n    }\n\n    @Test\n    public void shouldRewindOnEventInMiddleOfBatch()\n    {\n        int ringBufferEntries = 10;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(\n                values,\n                singletonList(rewind(8, 1)),\n                lastSequenceNumber,\n                -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 7),\n                event(0, lastSequenceNumber)));\n    }\n\n    @Test\n    public void shouldRewindOnLastEventOfBatch()\n    {\n        int ringBufferEntries = 10;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(\n                values,\n                singletonList(rewind(lastSequenceNumber, 1)),\n                lastSequenceNumber,\n                -1\n        );\n\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 8),\n                event(0, lastSequenceNumber)));\n    }\n\n    @Test\n    public void shouldRunBatchCompleteOnLastEventOfBatch()\n    {\n        int ringBufferEntries = 10;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values,\n                singletonList(rewind(4, 1)),\n                lastSequenceNumber,\n                -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 3),\n                event(0, lastSequenceNumber)));\n    }\n\n    @Test\n    public void shouldRunBatchCompleteOnLastEventOfBatchOfOne()\n    {\n        fill(ringBuffer, 1);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values, singletonList(rewind(0, 1)), 0, -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 0)));\n    }\n\n    @Test\n    public void shouldRewindMultipleTimes()\n    {\n        int ringBufferEntries = 10;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values,\n                singletonList(rewind(8, 3)),\n                lastSequenceNumber,\n                -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 7),\n                event(0, 7),\n                event(0, 7),\n                event(0, lastSequenceNumber)));\n    }\n\n    @Test\n    public void shouldRewindMultipleTimesOnLastEventInBatch()\n    {\n        int ringBufferEntries = 10;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values,\n                singletonList(rewind(lastSequenceNumber, 3)),\n                lastSequenceNumber,\n                -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 8),\n                event(0, 8),\n                event(0, 8),\n                event(0, lastSequenceNumber)));\n    }\n\n    @Test\n    public void shouldRewindMultipleTimesInSameBatch()\n    {\n        int ringBufferEntries = 10;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values,\n                asList(rewind(5, 3), rewind(7, 3)),\n                lastSequenceNumber,\n                -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 4),\n                event(0, 4),\n                event(0, 4),\n                event(0, 6),\n                event(0, 6),\n                event(0, 6),\n                event(0, lastSequenceNumber)));\n    }\n\n    @Test\n    public void shouldRewindMultipleTimesOnBatchOfOne()\n    {\n        fill(ringBuffer, 1);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values, singletonList(rewind(0, 3)), 0, -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        // nothing is actually written as first event is rewound\n        assertThat(values, containsExactSequence(\n                event(0, 0)));\n    }\n\n    @Test\n    public void shouldFallOverWhenNonRewindableExceptionIsThrown()\n    {\n        int ringBufferEntries = 10;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values, emptyList(), lastSequenceNumber, 8);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        AtomicReference<Throwable> exceptionHandled = new AtomicReference<>();\n        eventProcessor.setExceptionHandler(new StubExceptionHandler(exceptionHandled));\n        eventProcessor.run();\n        assertEquals(\"not rewindable\", exceptionHandled.get().getMessage());\n    }\n\n    @Test\n    public void shouldProcessUpToMaxBatchSizeForEachGivenBatch()\n    {\n        int ringBufferEntries = 30;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values, emptyList(), lastSequenceNumber, -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 9),\n                event(10, 19),\n                event(20, lastSequenceNumber)));\n    }\n\n    @Test\n    public void shouldOnlyRewindBatch()\n    {\n        int ringBufferEntries = 30;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values,\n                singletonList(rewind(15, 3)),\n                lastSequenceNumber,\n                -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler);\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 14),\n                event(0, 14),\n                event(0, 14),\n                event(0, lastSequenceNumber)));\n    }\n\n    @Test\n    void shouldInvokeRewindPauseStrategyOnRewind()\n    {\n        int ringBufferEntries = 30;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values,\n                singletonList(rewind(15, 3)),\n                lastSequenceNumber,\n                -1);\n        CountingBatchRewindStrategy rewindPauseStrategy = new CountingBatchRewindStrategy();\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler, rewindPauseStrategy);\n\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 14),\n                event(0, 14),\n                event(0, 14),\n                event(0, lastSequenceNumber)));\n\n        assertEquals(3, rewindPauseStrategy.count);\n    }\n\n    @Test\n    void shouldNotInvokeRewindPauseStrategyWhenNoRewindsOccur()\n    {\n        int ringBufferEntries = 30;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values,\n                singletonList(rewind(-1, -1)),\n                lastSequenceNumber,\n                -1);\n        CountingBatchRewindStrategy rewindPauseStrategy = new CountingBatchRewindStrategy();\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler, rewindPauseStrategy);\n\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, lastSequenceNumber)));\n\n        assertEquals(0, rewindPauseStrategy.count);\n    }\n\n    @Test\n    void shouldCopeWithTheNanosecondRewindPauseStrategy()\n    {\n        int ringBufferEntries = 30;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values,\n                singletonList(rewind(15, 3)),\n                lastSequenceNumber,\n                -1);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler, new NanosecondPauseBatchRewindStrategy(1000));\n\n        eventHandler.setRewindable(eventProcessor);\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 14),\n                event(0, 14),\n                event(0, 14),\n                event(0, lastSequenceNumber)));\n\n    }\n\n\n    @Test\n    void shouldGiveUpWhenUsingTheGiveUpRewindStrategy()\n    {\n        int ringBufferEntries = 30;\n        int lastSequenceNumber = ringBufferEntries - 1;\n        fill(ringBuffer, ringBufferEntries);\n\n        final TestEventHandler eventHandler = new TestEventHandler(values,\n                asList(rewind(15, 99), rewind(25, 99)),\n                lastSequenceNumber,\n                -1);\n        EventuallyGiveUpBatchRewindStrategy batchRewindStrategy = new EventuallyGiveUpBatchRewindStrategy(3);\n        final BatchEventProcessor<LongEvent> eventProcessor = create(eventHandler, batchRewindStrategy);\n\n        eventHandler.setRewindable(eventProcessor);\n\n        AtomicReference<Throwable> exceptionHandled = new AtomicReference<>();\n        eventProcessor.setExceptionHandler(new StubExceptionHandler(exceptionHandled));\n\n        eventProcessor.run();\n\n        assertThat(values, containsExactSequence(\n                event(0, 14),\n                event(0, 14),\n                event(0, 14),\n                event(16, 24), // unable to process 15 so it ends up skipping it\n                event(16, 24),\n                event(16, 24),\n                event(26, lastSequenceNumber))); // unable to process 25 so it ends up skipping it\n    }\n\n    @Test\n    void shouldNotAllowNullBatchRewindStrategy()\n    {\n        final TestEventHandler eventHandler = new TestEventHandler(values,\n                asList(rewind(15, 99), rewind(25, 99)),\n                -1,\n                -1);\n        final BatchEventProcessorBuilder batchEventProcessorBuilder = new BatchEventProcessorBuilder();\n        assertThrows(NullPointerException.class, () -> batchEventProcessorBuilder.build(ringBuffer, ringBuffer.newBarrier(), eventHandler, null));\n    }\n\n    private static ForceRewindSequence rewind(final long sequenceNumberToFailOn, final long timesToFail)\n    {\n        return new ForceRewindSequence(sequenceNumberToFailOn, timesToFail);\n    }\n\n    private EventRangeExpectation event(final long sequenceStart, final long sequenceEnd)\n    {\n        return new EventRangeExpectation(sequenceStart, sequenceEnd, false);\n    }\n\n    private BatchEventProcessor<LongEvent> create(final TestEventHandler eventHandler)\n    {\n        return create(eventHandler, new SimpleBatchRewindStrategy());\n    }\n\n    private BatchEventProcessor<LongEvent> create(final TestEventHandler eventHandler, final BatchRewindStrategy batchRewindStrategy)\n    {\n        return new BatchEventProcessorBuilder().build(\n                ringBuffer,\n                ringBuffer.newBarrier(),\n                eventHandler,\n                batchRewindStrategy);\n    }\n\n    private static final class TestEventHandler implements RewindableEventHandler<LongEvent>\n    {\n        private final List<EventResult> values;\n        private BatchEventProcessor<LongEvent> processor;\n        private final List<ForceRewindSequence> forceRewindSequences;\n        private final long exitValue;\n        private final int nonRewindableErrorSequence;\n\n        private TestEventHandler(\n                final List<EventResult> values,\n                final List<ForceRewindSequence> forceRewindSequences,\n                final long exitValue,\n                final int nonRewindableErrorSequence)\n        {\n            this.values = values;\n            this.forceRewindSequences = forceRewindSequences;\n            this.exitValue = exitValue;\n            this.nonRewindableErrorSequence = nonRewindableErrorSequence;\n        }\n\n\n        public void setRewindable(final BatchEventProcessor<LongEvent> processor)\n        {\n            this.processor = processor;\n        }\n\n        @Override\n        public void onEvent(final LongEvent event, final long sequence, final boolean endOfBatch) throws RewindableException\n        {\n\n            if (sequence == nonRewindableErrorSequence)\n            {\n                throw new RuntimeException(\"not rewindable\");\n            }\n\n            Optional<ForceRewindSequence> maybeForceRewindSequence = this.forceRewindSequences.stream()\n                    .filter(r -> r.sequenceNumberToFailOn == sequence).findFirst();\n\n            if (maybeForceRewindSequence.isPresent())\n            {\n                ForceRewindSequence forceRewindSequence = maybeForceRewindSequence.get();\n\n                if (forceRewindSequence.numberOfTimesRewound != forceRewindSequence.timesToFail)\n                {\n                    forceRewindSequence.numberOfTimesRewound++;\n                    throw new RewindableException(new RuntimeException());\n\n                }\n            }\n\n            values.add(new EventResult(event.get(), false));\n\n            if (sequence == exitValue)\n            {\n                processor.halt();\n            }\n        }\n    }\n\n    private static void fill(final RingBuffer<LongEvent> ringBuffer, final int batchSize)\n    {\n        for (long l = 0; l < batchSize; l++)\n        {\n            final long next = ringBuffer.next();\n            ringBuffer.get(next).set(l);\n            ringBuffer.publish(next);\n        }\n    }\n\n    private static Matcher<List<EventResult>> containsExactSequence(final EventRangeExpectation... ranges)\n    {\n        return new TypeSafeMatcher<>()\n        {\n            @Override\n            public void describeTo(final Description description)\n            {\n                description.appendValue(Arrays.toString(ranges));\n            }\n\n            @Override\n            public boolean matchesSafely(final List<EventResult> item)\n            {\n                int index = 0;\n                for (final EventRangeExpectation range : ranges)\n                {\n                    for (long v = range.sequenceStart, end = range.sequenceEnd; v <= end; v++)\n                    {\n                        final EventResult eventResult = item.get(index++);\n                        if (eventResult.sequence != v && eventResult.batchFinish != range.batchFinish)\n                        {\n                            return false;\n                        }\n                    }\n                }\n\n                return item.size() == index;\n            }\n        };\n    }\n\n    private static final class EventRangeExpectation\n    {\n        private final long sequenceStart;\n        private final long sequenceEnd;\n        private final boolean batchFinish;\n\n        EventRangeExpectation(final long sequenceStart, final long sequenceEnd, final boolean batchFinish)\n        {\n            this.sequenceStart = sequenceStart;\n            this.sequenceEnd = sequenceEnd;\n            this.batchFinish = batchFinish;\n        }\n\n        @Override\n        public String toString()\n        {\n            return \"{\" +\n                    sequenceStart +\n                    \",\" + sequenceEnd +\n                    \",\" + batchFinish +\n                    '}';\n        }\n    }\n\n\n    private static final class EventResult\n    {\n        final long sequence;\n        final boolean batchFinish;\n\n        private EventResult(final long sequence, final boolean batchFinish)\n        {\n            this.sequence = sequence;\n            this.batchFinish = batchFinish;\n        }\n\n        @Override\n        public String toString()\n        {\n            return \"{\" + sequence +\n                    \",\" + batchFinish +\n                    '}';\n        }\n    }\n\n    private static final class CountingBatchRewindStrategy implements BatchRewindStrategy\n    {\n        int count = 0;\n\n        @Override\n        public RewindAction handleRewindException(final RewindableException e, final int retriesAttempted)\n        {\n            count++;\n            return RewindAction.REWIND;\n        }\n\n    }\n\n    private static final class ForceRewindSequence\n    {\n        final long sequenceNumberToFailOn;\n        final long timesToFail;\n        long numberOfTimesRewound = 0;\n\n        private ForceRewindSequence(final long sequenceNumberToFailOn, final long timesToFail)\n        {\n            this.sequenceNumberToFailOn = sequenceNumberToFailOn;\n            this.timesToFail = timesToFail;\n        }\n    }\n}"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/RingBufferEventMatcher.java",
    "content": "package com.lmax.disruptor;\n\nimport org.hamcrest.Description;\nimport org.hamcrest.Matcher;\nimport org.hamcrest.TypeSafeMatcher;\n\nimport static org.hamcrest.CoreMatchers.is;\n\nfinal class RingBufferEventMatcher extends TypeSafeMatcher<RingBuffer<Object[]>>\n{\n    private final Matcher<?>[] expectedValueMatchers;\n\n    private RingBufferEventMatcher(final Matcher<?>[] expectedValueMatchers)\n    {\n        this.expectedValueMatchers = expectedValueMatchers;\n    }\n\n    public static RingBufferEventMatcher ringBufferWithEvents(final Matcher<?>... valueMatchers)\n    {\n        return new RingBufferEventMatcher(valueMatchers);\n    }\n\n    public static RingBufferEventMatcher ringBufferWithEvents(final Object... values)\n    {\n        Matcher<?>[] valueMatchers = new Matcher[values.length];\n        for (int i = 0; i < values.length; i++)\n        {\n            final Object value = values[i];\n            valueMatchers[i] = is(value);\n        }\n        return new RingBufferEventMatcher(valueMatchers);\n    }\n\n    @Override\n    public boolean matchesSafely(final RingBuffer<Object[]> ringBuffer)\n    {\n        boolean matches = true;\n        for (int i = 0; i < expectedValueMatchers.length; i++)\n        {\n            final Matcher<?> expectedValueMatcher = expectedValueMatchers[i];\n            matches &= expectedValueMatcher.matches(ringBuffer.get(i)[0]);\n        }\n        return matches;\n    }\n\n    @Override\n    public void describeTo(final Description description)\n    {\n        description.appendText(\"Expected ring buffer with events matching: \");\n\n        for (Matcher<?> expectedValueMatcher : expectedValueMatchers)\n        {\n            expectedValueMatcher.describeTo(description);\n        }\n    }\n}"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/RingBufferTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.StubEvent;\nimport com.lmax.disruptor.support.TestWaiter;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.List;\nimport java.util.concurrent.BrokenBarrierException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static com.lmax.disruptor.RingBuffer.createMultiProducer;\nimport static com.lmax.disruptor.RingBufferEventMatcher.ringBufferWithEvents;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.nullValue;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\npublic class RingBufferTest\n{\n    private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);\n    private final RingBuffer<StubEvent> ringBuffer = RingBuffer.createMultiProducer(StubEvent.EVENT_FACTORY, 32);\n    private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n\n    {\n        ringBuffer.addGatingSequences(new NoOpEventProcessor(ringBuffer).getSequence());\n    }\n\n    @Test\n    public void shouldClaimAndGet() throws Exception\n    {\n        assertEquals(SingleProducerSequencer.INITIAL_CURSOR_VALUE, ringBuffer.getCursor());\n\n        StubEvent expectedEvent = new StubEvent(2701);\n        ringBuffer.publishEvent(StubEvent.TRANSLATOR, expectedEvent.getValue(), expectedEvent.getTestString());\n\n        long sequence = sequenceBarrier.waitFor(0);\n        assertEquals(0, sequence);\n\n        StubEvent event = ringBuffer.get(sequence);\n        assertEquals(expectedEvent, event);\n\n        assertEquals(0L, ringBuffer.getCursor());\n    }\n\n    @Test\n    public void shouldClaimAndGetInSeparateThread() throws Exception\n    {\n        Future<List<StubEvent>> messages = getMessages(0, 0);\n\n        StubEvent expectedEvent = new StubEvent(2701);\n        ringBuffer.publishEvent(StubEvent.TRANSLATOR, expectedEvent.getValue(), expectedEvent.getTestString());\n\n        assertEquals(expectedEvent, messages.get().get(0));\n    }\n\n    @Test\n    public void shouldClaimAndGetMultipleMessages() throws Exception\n    {\n        int numMessages = ringBuffer.getBufferSize();\n        for (int i = 0; i < numMessages; i++)\n        {\n            ringBuffer.publishEvent(StubEvent.TRANSLATOR, i, \"\");\n        }\n\n        long expectedSequence = numMessages - 1;\n        long available = sequenceBarrier.waitFor(expectedSequence);\n        assertEquals(expectedSequence, available);\n\n        for (int i = 0; i < numMessages; i++)\n        {\n            assertEquals(i, ringBuffer.get(i).getValue());\n        }\n    }\n\n    @Test\n    public void shouldWrap() throws Exception\n    {\n        int numMessages = ringBuffer.getBufferSize();\n        int offset = 1000;\n        for (int i = 0; i < numMessages + offset; i++)\n        {\n            ringBuffer.publishEvent(StubEvent.TRANSLATOR, i, \"\");\n        }\n\n        long expectedSequence = numMessages + offset - 1;\n        long available = sequenceBarrier.waitFor(expectedSequence);\n        assertEquals(expectedSequence, available);\n\n        for (int i = offset; i < numMessages + offset; i++)\n        {\n            assertEquals(i, ringBuffer.get(i).getValue());\n        }\n    }\n\n    @Test\n    public void shouldPreventWrapping() throws Exception\n    {\n        Sequence sequence = new Sequence(Sequencer.INITIAL_CURSOR_VALUE);\n        final RingBuffer<StubEvent> ringBuffer = createMultiProducer(StubEvent.EVENT_FACTORY, 4);\n        ringBuffer.addGatingSequences(sequence);\n\n        ringBuffer.publishEvent(StubEvent.TRANSLATOR, 0, \"0\");\n        ringBuffer.publishEvent(StubEvent.TRANSLATOR, 1, \"1\");\n        ringBuffer.publishEvent(StubEvent.TRANSLATOR, 2, \"2\");\n        ringBuffer.publishEvent(StubEvent.TRANSLATOR, 3, \"3\");\n\n        assertFalse(ringBuffer.tryPublishEvent(StubEvent.TRANSLATOR, 3, \"3\"));\n    }\n\n    @Test\n    public void shouldThrowExceptionIfBufferIsFull() throws Exception\n    {\n        ringBuffer.addGatingSequences(new Sequence(ringBuffer.getBufferSize()));\n\n        for (int i = 0; i < ringBuffer.getBufferSize(); i++)\n        {\n            ringBuffer.publish(ringBuffer.tryNext());\n        }\n\n        assertThrows(InsufficientCapacityException.class, ringBuffer::tryNext);\n    }\n\n    @Test\n    public void shouldPreventPublishersOvertakingEventProcessorWrapPoint() throws InterruptedException\n    {\n        final int ringBufferSize = 16;\n        final CountDownLatch latch = new CountDownLatch(ringBufferSize);\n        final AtomicBoolean publisherComplete = new AtomicBoolean(false);\n        final RingBuffer<StubEvent> buffer2 = createMultiProducer(StubEvent.EVENT_FACTORY, ringBufferSize);\n        final TestEventProcessor processor = new TestEventProcessor(buffer2.newBarrier());\n        buffer2.addGatingSequences(processor.getSequence());\n\n        Thread thread = new Thread(\n                () ->\n                {\n                    // Attempt to put in enough events to wrap around the ringbuffer\n                    for (int i = 0; i < ringBufferSize + 1; i++)\n                    {\n                        long sequence = buffer2.next();\n                        StubEvent event = buffer2.get(sequence);\n                        event.setValue(i);\n                        buffer2.publish(sequence);\n                        latch.countDown();\n                    }\n\n                    // Only marked complete after enough events published that the ringbuffer must have wrapped\n                    publisherComplete.set(true);\n                });\n        thread.start();\n\n        latch.await();\n\n        // Publisher should not be complete, blocked at RingBuffer::next\n        assertFalse(publisherComplete.get());\n\n        // Run the processor, freeing up entries in the ringbuffer for the producer to continue and \"complete\"\n        processor.run();\n        thread.join();\n\n        // Check producer completes, ideally this should be in some kind of waiter\n        assertTrue(publisherComplete.get());\n    }\n\n    @Test\n    public void shouldPublishEvent() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        final EventTranslator<Object[]> translator = new NoArgEventTranslator();\n\n        ringBuffer.publishEvent(translator);\n        ringBuffer.tryPublishEvent(translator);\n\n        assertThat(ringBuffer, ringBufferWithEvents(0L, 1L));\n    }\n\n    @Test\n    public void shouldPublishEventOneArg() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n        ringBuffer.publishEvent(translator, \"Foo\");\n        ringBuffer.tryPublishEvent(translator, \"Foo\");\n\n        assertThat(ringBuffer, ringBufferWithEvents(\"Foo-0\", \"Foo-1\"));\n    }\n\n    @Test\n    public void shouldPublishEventTwoArg() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n        ringBuffer.publishEvent(translator, \"Foo\", \"Bar\");\n        ringBuffer.tryPublishEvent(translator, \"Foo\", \"Bar\");\n\n        assertThat(ringBuffer, ringBufferWithEvents(\"FooBar-0\", \"FooBar-1\"));\n    }\n\n    @Test\n    public void shouldPublishEventThreeArg() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n        ringBuffer.publishEvent(translator, \"Foo\", \"Bar\", \"Baz\");\n        ringBuffer.tryPublishEvent(translator, \"Foo\", \"Bar\", \"Baz\");\n\n        assertThat(ringBuffer, ringBufferWithEvents(\"FooBarBaz-0\", \"FooBarBaz-1\"));\n    }\n\n    @Test\n    public void shouldPublishEventVarArg() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorVararg<Object[]> translator = new VarArgEventTranslator();\n\n        ringBuffer.publishEvent(translator, \"Foo\", \"Bar\", \"Baz\", \"Bam\");\n        ringBuffer.tryPublishEvent(translator, \"Foo\", \"Bar\", \"Baz\", \"Bam\");\n\n        assertThat(ringBuffer, ringBufferWithEvents(\"FooBarBazBam-0\", \"FooBarBazBam-1\"));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldPublishEvents() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        final EventTranslator<Object[]> eventTranslator = new NoArgEventTranslator();\n        final EventTranslator<Object[]>[] translators = new EventTranslator[]{eventTranslator, eventTranslator};\n\n        ringBuffer.publishEvents(translators);\n        assertTrue(ringBuffer.tryPublishEvents(translators));\n\n        assertThat(ringBuffer, ringBufferWithEvents(0L, 1L, 2L, 3L));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldNotPublishEventsIfBatchIsLargerThanRingBuffer() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            final EventTranslator<Object[]> eventTranslator = new NoArgEventTranslator();\n            final EventTranslator<Object[]>[] translators =\n                    new EventTranslator[]{eventTranslator, eventTranslator, eventTranslator, eventTranslator, eventTranslator};\n\n            try\n            {\n                ringBuffer.tryPublishEvents(translators);\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldPublishEventsWithBatchSizeOfOne() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        final EventTranslator<Object[]> eventTranslator = new NoArgEventTranslator();\n        final EventTranslator<Object[]>[] translators =\n            new EventTranslator[]{eventTranslator, eventTranslator, eventTranslator};\n\n        ringBuffer.publishEvents(translators, 0, 1);\n        assertTrue(ringBuffer.tryPublishEvents(translators, 0, 1));\n\n        assertThat(\n            ringBuffer, ringBufferWithEvents(\n                is((Object) 0L), is((Object) 1L), is(nullValue()), is(\n                    nullValue())));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldPublishEventsWithinBatch() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        final EventTranslator<Object[]> eventTranslator = new NoArgEventTranslator();\n        final EventTranslator<Object[]>[] translators =\n            new EventTranslator[]{eventTranslator, eventTranslator, eventTranslator};\n\n        ringBuffer.publishEvents(translators, 1, 2);\n        assertTrue(ringBuffer.tryPublishEvents(translators, 1, 2));\n\n        assertThat(ringBuffer, ringBufferWithEvents(0L, 1L, 2L, 3L));\n    }\n\n    @Test\n    public void shouldPublishEventsOneArg() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n        ringBuffer.publishEvents(translator, new String[]{\"Foo\", \"Foo\"});\n        assertTrue(ringBuffer.tryPublishEvents(translator, new String[]{\"Foo\", \"Foo\"}));\n\n        assertThat(ringBuffer, ringBufferWithEvents(\"Foo-0\", \"Foo-1\", \"Foo-2\", \"Foo-3\"));\n    }\n\n    @Test\n    public void shouldNotPublishEventsOneArgIfBatchIsLargerThanRingBuffer() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(translator, new String[]{\"Foo\", \"Foo\", \"Foo\", \"Foo\", \"Foo\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldPublishEventsOneArgBatchSizeOfOne() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n        ringBuffer.publishEvents(translator, 0, 1, new String[]{\"Foo\", \"Foo\"});\n        assertTrue(ringBuffer.tryPublishEvents(translator, 0, 1, new String[]{\"Foo\", \"Foo\"}));\n\n        assertThat(\n            ringBuffer, ringBufferWithEvents(\n                is((Object) \"Foo-0\"), is((Object) \"Foo-1\"), is(nullValue()), is(\n                    nullValue())));\n    }\n\n    @Test\n    public void shouldPublishEventsOneArgWithinBatch() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n        ringBuffer.publishEvents(translator, 1, 2, new String[]{\"Foo\", \"Foo\", \"Foo\"});\n        assertTrue(ringBuffer.tryPublishEvents(translator, 1, 2, new String[]{\"Foo\", \"Foo\", \"Foo\"}));\n\n        assertThat(ringBuffer, ringBufferWithEvents(\"Foo-0\", \"Foo-1\", \"Foo-2\", \"Foo-3\"));\n    }\n\n    @Test\n    public void shouldPublishEventsTwoArg() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n        ringBuffer.publishEvents(translator, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"});\n        ringBuffer.tryPublishEvents(translator, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"});\n\n        assertThat(ringBuffer, ringBufferWithEvents(\"FooBar-0\", \"FooBar-1\", \"FooBar-2\", \"FooBar-3\"));\n    }\n\n    @Test\n    public void shouldNotPublishEventsITwoArgIfBatchSizeIsBiggerThanRingBuffer() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(\n                        translator,\n                        new String[]{\"Foo\", \"Foo\", \"Foo\", \"Foo\", \"Foo\"},\n                        new String[]{\"Bar\", \"Bar\", \"Bar\", \"Bar\", \"Bar\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldPublishEventsTwoArgWithBatchSizeOfOne() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n        ringBuffer.publishEvents(translator, 0, 1, new String[]{\"Foo0\", \"Foo1\"}, new String[]{\"Bar0\", \"Bar1\"});\n        ringBuffer.tryPublishEvents(translator, 0, 1, new String[]{\"Foo2\", \"Foo3\"}, new String[]{\"Bar2\", \"Bar3\"});\n\n        assertThat(\n            ringBuffer, ringBufferWithEvents(\n                is((Object) \"Foo0Bar0-0\"), is((Object) \"Foo2Bar2-1\"), is(\n                    nullValue()), is(nullValue())));\n    }\n\n    @Test\n    public void shouldPublishEventsTwoArgWithinBatch() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n        ringBuffer.publishEvents(\n            translator, 1, 2, new String[]{\"Foo0\", \"Foo1\", \"Foo2\"}, new String[]{\"Bar0\", \"Bar1\", \"Bar2\"});\n        ringBuffer.tryPublishEvents(\n            translator, 1, 2, new String[]{\"Foo3\", \"Foo4\", \"Foo5\"}, new String[]{\"Bar3\", \"Bar4\", \"Bar5\"});\n\n        assertThat(ringBuffer, ringBufferWithEvents(\"Foo1Bar1-0\", \"Foo2Bar2-1\", \"Foo4Bar4-2\", \"Foo5Bar5-3\"));\n    }\n\n    @Test\n    public void shouldPublishEventsThreeArg() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n        ringBuffer.publishEvents(\n            translator, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"}, new String[]{\"Baz\", \"Baz\"});\n        ringBuffer.tryPublishEvents(\n            translator, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"}, new String[]{\"Baz\", \"Baz\"});\n\n        assertThat(ringBuffer, ringBufferWithEvents(\"FooBarBaz-0\", \"FooBarBaz-1\", \"FooBarBaz-2\", \"FooBarBaz-3\"));\n    }\n\n    @Test\n    public void shouldNotPublishEventsThreeArgIfBatchIsLargerThanRingBuffer() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(\n                        translator,\n                        new String[]{\"Foo\", \"Foo\", \"Foo\", \"Foo\", \"Foo\"},\n                        new String[]{\"Bar\", \"Bar\", \"Bar\", \"Bar\", \"Bar\"},\n                        new String[]{\"Baz\", \"Baz\", \"Baz\", \"Baz\", \"Baz\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldPublishEventsThreeArgBatchSizeOfOne() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n        ringBuffer.publishEvents(\n            translator, 0, 1, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"}, new String[]{\"Baz\", \"Baz\"});\n        ringBuffer.tryPublishEvents(\n            translator, 0, 1, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"}, new String[]{\"Baz\", \"Baz\"});\n\n        assertThat(\n            ringBuffer, ringBufferWithEvents(\n                is((Object) \"FooBarBaz-0\"), is((Object) \"FooBarBaz-1\"), is(\n                    nullValue()), is(nullValue())));\n    }\n\n    @Test\n    public void shouldPublishEventsThreeArgWithinBatch() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n        ringBuffer.publishEvents(\n            translator, 1, 2, new String[]{\"Foo0\", \"Foo1\", \"Foo2\"}, new String[]{\"Bar0\", \"Bar1\", \"Bar2\"},\n            new String[]{\"Baz0\", \"Baz1\", \"Baz2\"}\n        );\n        assertTrue(\n            ringBuffer.tryPublishEvents(\n                translator, 1, 2, new String[]{\"Foo3\", \"Foo4\", \"Foo5\"}, new String[]{\"Bar3\", \"Bar4\", \"Bar5\"},\n                new String[]{\"Baz3\", \"Baz4\", \"Baz5\"}));\n\n        assertThat(\n            ringBuffer, ringBufferWithEvents(\n                \"Foo1Bar1Baz1-0\", \"Foo2Bar2Baz2-1\", \"Foo4Bar4Baz4-2\", \"Foo5Bar5Baz5-3\"));\n    }\n\n    @Test\n    public void shouldPublishEventsVarArg() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorVararg<Object[]> translator = new VarArgEventTranslator();\n\n        ringBuffer.publishEvents(\n            translator, new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"}, new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"});\n        assertTrue(\n            ringBuffer.tryPublishEvents(\n                translator, new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"}, new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"}));\n\n        assertThat(\n            ringBuffer, ringBufferWithEvents(\n                \"FooBarBazBam-0\", \"FooBarBazBam-1\", \"FooBarBazBam-2\", \"FooBarBazBam-3\"));\n    }\n\n    @Test\n    public void shouldNotPublishEventsVarArgIfBatchIsLargerThanRingBuffer() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorVararg<Object[]> translator = new VarArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(\n                        translator,\n                        new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"},\n                        new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"},\n                        new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"},\n                        new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"},\n                        new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldPublishEventsVarArgBatchSizeOfOne() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorVararg<Object[]> translator = new VarArgEventTranslator();\n\n        ringBuffer.publishEvents(\n            translator, 0, 1, new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"}, new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"});\n        assertTrue(\n            ringBuffer.tryPublishEvents(\n                translator, 0, 1, new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"}, new String[]{\"Foo\", \"Bar\", \"Baz\", \"Bam\"}));\n\n        assertThat(\n            ringBuffer, ringBufferWithEvents(\n                is((Object) \"FooBarBazBam-0\"), is((Object) \"FooBarBazBam-1\"), is(\n                    nullValue()), is(nullValue())));\n    }\n\n    @Test\n    public void shouldPublishEventsVarArgWithinBatch() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n        EventTranslatorVararg<Object[]> translator = new VarArgEventTranslator();\n\n        ringBuffer.publishEvents(\n            translator, 1, 2, new String[]{\"Foo0\", \"Bar0\", \"Baz0\", \"Bam0\"},\n            new String[]{\"Foo1\", \"Bar1\", \"Baz1\", \"Bam1\"},\n            new String[]{\"Foo2\", \"Bar2\", \"Baz2\", \"Bam2\"});\n        assertTrue(\n            ringBuffer.tryPublishEvents(\n                translator, 1, 2, new String[]{\"Foo3\", \"Bar3\", \"Baz3\", \"Bam3\"},\n                new String[]{\"Foo4\", \"Bar4\", \"Baz4\", \"Bam4\"},\n                new String[]{\"Foo5\", \"Bar5\", \"Baz5\", \"Bam5\"}));\n\n        assertThat(\n            ringBuffer, ringBufferWithEvents(\n                \"Foo1Bar1Baz1Bam1-0\", \"Foo2Bar2Baz2Bam2-1\", \"Foo4Bar4Baz4Bam4-2\", \"Foo5Bar5Baz5Bam5-3\"));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldNotPublishEventsWhenBatchSizeIs0() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslator<Object[]> translator = new NoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(new EventTranslator[]{translator, translator, translator, translator}, 1, 0);\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldNotTryPublishEventsWhenBatchSizeIs0() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslator<Object[]> translator = new NoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(new EventTranslator[]{translator, translator, translator, translator}, 1, 0);\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldNotPublishEventsWhenBatchExtendsPastEndOfArray() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslator<Object[]> translator = new NoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(new EventTranslator[]{translator, translator, translator}, 1, 3);\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldNotTryPublishEventsWhenBatchExtendsPastEndOfArray() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslator<Object[]> translator = new NoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(new EventTranslator[]{translator, translator, translator}, 1, 3);\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldNotPublishEventsWhenBatchSizeIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslator<Object[]> translator = new NoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(new EventTranslator[]{translator, translator, translator, translator}, 1, -1);\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldNotTryPublishEventsWhenBatchSizeIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslator<Object[]> translator = new NoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(new EventTranslator[]{translator, translator, translator, translator}, 1, -1);\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldNotPublishEventsWhenBatchStartsAtIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslator<Object[]> translator = new NoArgEventTranslator();\n            try\n            {\n                ringBuffer.publishEvents(new EventTranslator[]{translator, translator, translator, translator}, -1, 2);\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldNotTryPublishEventsWhenBatchStartsAtIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslator<Object[]> translator = new NoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(new EventTranslator[]{translator, translator, translator, translator}, -1, 2);\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsOneArgWhenBatchSizeIs0() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(translator, 1, 0, new String[]{\"Foo\", \"Foo\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsOneArgWhenBatchSizeIs0() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(translator, 1, 0, new String[]{\"Foo\", \"Foo\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsOneArgWhenBatchExtendsPastEndOfArray() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(translator, 1, 3, new String[]{\"Foo\", \"Foo\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsOneArgWhenBatchSizeIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(translator, 1, -1, new String[]{\"Foo\", \"Foo\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsOneArgWhenBatchStartsAtIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n            try\n            {\n                ringBuffer.publishEvents(translator, -1, 2, new String[]{\"Foo\", \"Foo\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsOneArgWhenBatchExtendsPastEndOfArray() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(translator, 1, 3, new String[]{\"Foo\", \"Foo\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsOneArgWhenBatchSizeIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n            try\n            {\n                assertFalse(ringBuffer.tryPublishEvents(translator, 1, -1, new String[]{\"Foo\", \"Foo\"}));\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsOneArgWhenBatchStartsAtIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorOneArg<Object[], String> translator = new OneArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(translator, -1, 2, new String[]{\"Foo\", \"Foo\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsTwoArgWhenBatchSizeIs0() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(translator, 1, 0, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsTwoArgWhenBatchSizeIs0() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(translator, 1, 0, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsTwoArgWhenBatchExtendsPastEndOfArray() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(translator, 1, 3, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsTwoArgWhenBatchSizeIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(translator, 1, -1, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsTwoArgWhenBatchStartsAtIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n            try\n            {\n                ringBuffer.publishEvents(translator, -1, 2, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsTwoArgWhenBatchExtendsPastEndOfArray() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(translator, 1, 3, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsTwoArgWhenBatchSizeIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(translator, 1, -1, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsTwoArgWhenBatchStartsAtIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorTwoArg<Object[], String, String> translator = new TwoArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(translator, -1, 2, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsThreeArgWhenBatchSizeIs0() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(\n                        translator, 1, 0, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"},\n                        new String[]{\"Baz\", \"Baz\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsThreeArgWhenBatchSizeIs0() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(\n                        translator, 1, 0, new String[]{\"Foo\", \"Foo\"},\n                        new String[]{\"Bar\", \"Bar\"}, new String[]{\"Baz\", \"Baz\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsThreeArgWhenBatchExtendsPastEndOfArray() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(\n                        translator, 1, 3, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"},\n                        new String[]{\"Baz\", \"Baz\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsThreeArgWhenBatchSizeIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(\n                        translator, 1, -1, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"},\n                        new String[]{\"Baz\", \"Baz\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsThreeArgWhenBatchStartsAtIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(\n                        translator, -1, 2, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"},\n                        new String[]{\"Baz\", \"Baz\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsThreeArgWhenBatchExtendsPastEndOfArray() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(\n                        translator, 1, 3, new String[]{\"Foo\", \"Foo\"}, new String[]{\"Bar\", \"Bar\"},\n                        new String[]{\"Baz\", \"Baz\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsThreeArgWhenBatchSizeIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(\n                        translator, 1, -1, new String[]{\"Foo\", \"Foo\"},\n                        new String[]{\"Bar\", \"Bar\"}, new String[]{\"Baz\", \"Baz\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsThreeArgWhenBatchStartsAtIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            EventTranslatorThreeArg<Object[], String, String, String> translator = new ThreeArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(\n                        translator, -1, 2, new String[]{\"Foo\", \"Foo\"},\n                        new String[]{\"Bar\", \"Bar\"}, new String[]{\"Baz\", \"Baz\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsVarArgWhenBatchSizeIs0() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            VarArgEventTranslator translator = new VarArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(\n                        translator, 1, 0, new String[]{\"Foo0\", \"Bar0\", \"Baz0\", \"Bam0\"},\n                        new String[]{\"Foo1\", \"Bar1\", \"Baz1\", \"Bam1\"}, new String[]{\n                                \"Foo2\", \"Bar2\",\n                                \"Baz2\", \"Bam2\"\n                        });\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsVarArgWhenBatchSizeIs0() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            VarArgEventTranslator translator = new VarArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(\n                        translator, 1, 0, new String[]{\"Foo0\", \"Bar0\", \"Baz0\", \"Bam0\"},\n                        new String[]{\"Foo1\", \"Bar1\", \"Baz1\", \"Bam1\"},\n                        new String[]{\"Foo2\", \"Bar2\", \"Baz2\", \"Bam2\"});\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsVarArgWhenBatchExtendsPastEndOfArray() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            VarArgEventTranslator translator = new VarArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(\n                        translator, 1, 3, new String[]{\"Foo0\", \"Bar0\", \"Baz0\", \"Bam0\"},\n                        new String[]{\"Foo1\", \"Bar1\", \"Baz1\", \"Bam1\"}, new String[]{\n                                \"Foo2\", \"Bar2\",\n                                \"Baz2\", \"Bam2\"\n                        });\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsVarArgWhenBatchSizeIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            VarArgEventTranslator translator = new VarArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(\n                        translator, 1, -1, new String[]{\"Foo0\", \"Bar0\", \"Baz0\", \"Bam0\"},\n                        new String[]{\"Foo1\", \"Bar1\", \"Baz1\", \"Bam1\"}, new String[]{\n                                \"Foo2\", \"Bar2\",\n                                \"Baz2\", \"Bam2\"\n                        });\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotPublishEventsVarArgWhenBatchStartsAtIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            VarArgEventTranslator translator = new VarArgEventTranslator();\n\n            try\n            {\n                ringBuffer.publishEvents(\n                        translator, -1, 2, new String[]{\"Foo0\", \"Bar0\", \"Baz0\", \"Bam0\"},\n                        new String[]{\"Foo1\", \"Bar1\", \"Baz1\", \"Bam1\"}, new String[]{\n                                \"Foo2\", \"Bar2\",\n                                \"Baz2\", \"Bam2\"\n                        });\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsVarArgWhenBatchExtendsPastEndOfArray() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            VarArgEventTranslator translator = new VarArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(\n                        translator, 1, 3, new String[]{\"Foo0\", \"Bar0\", \"Baz0\", \"Bam0\"},\n                        new String[]{\"Foo1\", \"Bar1\", \"Baz1\", \"Bam1\"}, new String[]{\n                                \"Foo2\", \"Bar2\",\n                                \"Baz2\", \"Bam2\"\n                        });\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsVarArgWhenBatchSizeIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            VarArgEventTranslator translator = new VarArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(\n                        translator, 1, -1, new String[]{\"Foo0\", \"Bar0\", \"Baz0\", \"Bam0\"},\n                        new String[]{\"Foo1\", \"Bar1\", \"Baz1\", \"Bam1\"}, new String[]{\n                                \"Foo2\", \"Bar2\",\n                                \"Baz2\", \"Bam2\"\n                        });\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldNotTryPublishEventsVarArgWhenBatchStartsAtIsNegative() throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 4);\n            VarArgEventTranslator translator = new VarArgEventTranslator();\n\n            try\n            {\n                ringBuffer.tryPublishEvents(\n                        translator, -1, 2, new String[]{\"Foo0\", \"Bar0\", \"Baz0\", \"Bam0\"},\n                        new String[]{\"Foo1\", \"Bar1\", \"Baz1\", \"Bam1\"}, new String[]{\n                                \"Foo2\", \"Bar2\",\n                                \"Baz2\", \"Bam2\"\n                        });\n            }\n            finally\n            {\n                assertEmptyRingBuffer(ringBuffer);\n            }\n        });\n    }\n\n    @Test\n    public void shouldAddAndRemoveSequences() throws Exception\n    {\n        RingBuffer<Object[]> ringBuffer = RingBuffer.createSingleProducer(new ArrayFactory(1), 16);\n\n        Sequence sequenceThree = new Sequence(-1);\n        Sequence sequenceSeven = new Sequence(-1);\n        ringBuffer.addGatingSequences(sequenceThree, sequenceSeven);\n\n        for (int i = 0; i < 10; i++)\n        {\n            ringBuffer.publish(ringBuffer.next());\n        }\n\n        sequenceThree.set(3);\n        sequenceSeven.set(7);\n\n        assertThat(ringBuffer.getMinimumGatingSequence(), is(3L));\n        assertTrue(ringBuffer.removeGatingSequence(sequenceThree));\n        assertThat(ringBuffer.getMinimumGatingSequence(), is(7L));\n    }\n\n    private Future<List<StubEvent>> getMessages(final long initial, final long toWaitFor) throws InterruptedException,\n        BrokenBarrierException\n    {\n        final CyclicBarrier cyclicBarrier = new CyclicBarrier(2);\n        final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n\n        final Future<List<StubEvent>> f = executor.submit(\n            new TestWaiter(\n                cyclicBarrier, sequenceBarrier, ringBuffer,\n                initial, toWaitFor));\n\n        cyclicBarrier.await();\n\n        return f;\n    }\n\n    private void assertEmptyRingBuffer(final RingBuffer<Object[]> ringBuffer)\n    {\n        assertThat(ringBuffer.get(0)[0], is(nullValue()));\n        assertThat(ringBuffer.get(1)[0], is(nullValue()));\n        assertThat(ringBuffer.get(2)[0], is(nullValue()));\n        assertThat(ringBuffer.get(3)[0], is(nullValue()));\n    }\n\n    private static final class TestEventProcessor implements EventProcessor\n    {\n        private final SequenceBarrier sequenceBarrier;\n        private final Sequence sequence = new Sequence(SingleProducerSequencer.INITIAL_CURSOR_VALUE);\n        private final AtomicBoolean running = new AtomicBoolean();\n\n\n        TestEventProcessor(final SequenceBarrier sequenceBarrier)\n        {\n            this.sequenceBarrier = sequenceBarrier;\n        }\n\n        @Override\n        public Sequence getSequence()\n        {\n            return sequence;\n        }\n\n        @Override\n        public void halt()\n        {\n            running.set(false);\n        }\n\n        @Override\n        public boolean isRunning()\n        {\n            return running.get();\n        }\n\n        @Override\n        public void run()\n        {\n            if (!running.compareAndSet(false, true))\n            {\n                throw new IllegalStateException(\"Already running\");\n            }\n            try\n            {\n                sequenceBarrier.waitFor(0L);\n            }\n            catch (Exception ex)\n            {\n                throw new RuntimeException(ex);\n            }\n\n            sequence.set(sequence.get() + 1L);\n        }\n    }\n\n    private static class ArrayFactory implements EventFactory<Object[]>\n    {\n        private final int size;\n\n        ArrayFactory(final int size)\n        {\n            this.size = size;\n        }\n\n        @Override\n        public Object[] newInstance()\n        {\n            return new Object[size];\n        }\n    }\n\n    private static class NoArgEventTranslator implements EventTranslator<Object[]>\n    {\n        @Override\n        public void translateTo(final Object[] event, final long sequence)\n        {\n            event[0] = sequence;\n        }\n    }\n\n    private static class VarArgEventTranslator implements EventTranslatorVararg<Object[]>\n    {\n        @Override\n        public void translateTo(final Object[] event, final long sequence, final Object... args)\n        {\n            event[0] = (String) args[0] + args[1] + args[2] + args[3] + \"-\" + sequence;\n        }\n    }\n\n    private static class ThreeArgEventTranslator implements EventTranslatorThreeArg<Object[], String, String, String>\n    {\n        @Override\n        public void translateTo(final Object[] event, final long sequence, final String arg0, final String arg1, final String arg2)\n        {\n            event[0] = arg0 + arg1 + arg2 + \"-\" + sequence;\n        }\n    }\n\n    private static class TwoArgEventTranslator implements EventTranslatorTwoArg<Object[], String, String>\n    {\n        @Override\n        public void translateTo(final Object[] event, final long sequence, final String arg0, final String arg1)\n        {\n            event[0] = arg0 + arg1 + \"-\" + sequence;\n        }\n    }\n\n    private static class OneArgEventTranslator implements EventTranslatorOneArg<Object[], String>\n    {\n        @Override\n        public void translateTo(final Object[] event, final long sequence, final String arg0)\n        {\n            event[0] = arg0 + \"-\" + sequence;\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/RingBufferWithAssertingStubTest.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.StubEvent;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.ThreadLocalRandom;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.Is.is;\n\npublic class RingBufferWithAssertingStubTest\n{\n    private RingBuffer<StubEvent> ringBuffer;\n    private Sequencer sequencer;\n\n    @BeforeEach\n    public void setUp()\n    {\n        sequencer = new AssertingSequencer(16);\n\n        ringBuffer = new RingBuffer<>(StubEvent.EVENT_FACTORY, sequencer);\n    }\n\n    @Test\n    public void shouldDelegateNextAndPublish()\n    {\n        ringBuffer.publish(ringBuffer.next());\n    }\n\n    @Test\n    public void shouldDelegateTryNextAndPublish() throws Exception\n    {\n        ringBuffer.publish(ringBuffer.tryNext());\n    }\n\n    @Test\n    public void shouldDelegateNextNAndPublish() throws Exception\n    {\n        long hi = ringBuffer.next(10);\n        ringBuffer.publish(hi - 9, hi);\n    }\n\n    @Test\n    public void shouldDelegateTryNextNAndPublish() throws Exception\n    {\n        long hi = ringBuffer.tryNext(10);\n        ringBuffer.publish(hi - 9, hi);\n    }\n\n    private static final class AssertingSequencer implements Sequencer\n    {\n        private final int size;\n        private long lastBatchSize = -1;\n        private long lastValue = -1;\n\n        private AssertingSequencer(final int size)\n        {\n            this.size = size;\n        }\n\n        @Override\n        public int getBufferSize()\n        {\n            return size;\n        }\n\n        @Override\n        public boolean hasAvailableCapacity(final int requiredCapacity)\n        {\n            return requiredCapacity <= size;\n        }\n\n        @Override\n        public long remainingCapacity()\n        {\n            return size;\n        }\n\n        @Override\n        public long next()\n        {\n            lastValue = ThreadLocalRandom.current().nextLong(0, 1000000);\n            lastBatchSize = 1;\n            return lastValue;\n        }\n\n        @Override\n        public long next(final int n)\n        {\n            lastValue = ThreadLocalRandom.current().nextLong(n, 1000000);\n            lastBatchSize = n;\n            return lastValue;\n        }\n\n        @Override\n        public long tryNext() throws InsufficientCapacityException\n        {\n            return next();\n        }\n\n        @Override\n        public long tryNext(final int n) throws InsufficientCapacityException\n        {\n            return next(n);\n        }\n\n        @Override\n        public void publish(final long sequence)\n        {\n            assertThat(sequence, is(lastValue));\n            assertThat(lastBatchSize, is(1L));\n        }\n\n        @Override\n        public void publish(final long lo, final long hi)\n        {\n            assertThat(hi, is(lastValue));\n            assertThat((hi - lo) + 1, is(lastBatchSize));\n        }\n\n        @Override\n        public long getCursor()\n        {\n            return lastValue;\n        }\n\n        @Override\n        public void claim(final long sequence)\n        {\n\n        }\n\n        @Override\n        public boolean isAvailable(final long sequence)\n        {\n            return false;\n        }\n\n        @Override\n        public void addGatingSequences(final Sequence... gatingSequences)\n        {\n\n        }\n\n        @Override\n        public boolean removeGatingSequence(final Sequence sequence)\n        {\n            return false;\n        }\n\n        @Override\n        public SequenceBarrier newBarrier(final Sequence... sequencesToTrack)\n        {\n            return null;\n        }\n\n        @Override\n        public long getMinimumSequence()\n        {\n            return 0;\n        }\n\n        @Override\n        public long getHighestPublishedSequence(final long nextSequence, final long availableSequence)\n        {\n            return 0;\n        }\n\n        @Override\n        public <T> EventPoller<T> newPoller(final DataProvider<T> provider, final Sequence... gatingSequences)\n        {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/SequenceBarrierTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.DummyEventProcessor;\nimport com.lmax.disruptor.support.StubEvent;\nimport com.lmax.disruptor.util.Util;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport static com.lmax.disruptor.RingBuffer.createMultiProducer;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n\npublic final class SequenceBarrierTest\n{\n    private final RingBuffer<StubEvent> ringBuffer = createMultiProducer(StubEvent.EVENT_FACTORY, 64);\n\n    public SequenceBarrierTest()\n    {\n        ringBuffer.addGatingSequences(new NoOpEventProcessor(ringBuffer).getSequence());\n    }\n\n    @Test\n    public void shouldWaitForWorkCompleteWhereCompleteWorkThresholdIsAhead() throws Exception\n    {\n        final long expectedNumberMessages = 10;\n        final long expectedWorkSequence = 9;\n        fillRingBuffer(expectedNumberMessages);\n\n        final Sequence sequence1 = new Sequence(expectedNumberMessages);\n        final Sequence sequence2 = new Sequence(expectedWorkSequence);\n        final Sequence sequence3 = new Sequence(expectedNumberMessages);\n\n        final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(sequence1, sequence2, sequence3);\n\n        long completedWorkSequence = sequenceBarrier.waitFor(expectedWorkSequence);\n        assertTrue(completedWorkSequence >= expectedWorkSequence);\n    }\n\n    @Test\n    public void shouldWaitForWorkCompleteWhereAllWorkersAreBlockedOnRingBuffer() throws Exception\n    {\n        long expectedNumberMessages = 10;\n        fillRingBuffer(expectedNumberMessages);\n\n        final DummyEventProcessor[] workers = new DummyEventProcessor[3];\n        for (int i = 0, size = workers.length; i < size; i++)\n        {\n            workers[i] = new DummyEventProcessor();\n            workers[i].setSequence(expectedNumberMessages - 1);\n        }\n\n        final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(Util.getSequencesFor(workers));\n\n        Runnable runnable = () ->\n        {\n            long sequence = ringBuffer.next();\n            StubEvent event = ringBuffer.get(sequence);\n            event.setValue((int) sequence);\n            ringBuffer.publish(sequence);\n\n            for (DummyEventProcessor stubWorker : workers)\n            {\n                stubWorker.setSequence(sequence);\n            }\n        };\n\n        new Thread(runnable).start();\n\n        long expectedWorkSequence = expectedNumberMessages;\n        long completedWorkSequence = sequenceBarrier.waitFor(expectedNumberMessages);\n        assertTrue(completedWorkSequence >= expectedWorkSequence);\n    }\n\n    @Test\n    public void shouldInterruptDuringBusySpin() throws Exception\n    {\n        final long expectedNumberMessages = 10;\n        fillRingBuffer(expectedNumberMessages);\n\n        final CountDownLatch latch = new CountDownLatch(3);\n        final Sequence sequence1 = new CountDownLatchSequence(8L, latch);\n        final Sequence sequence2 = new CountDownLatchSequence(8L, latch);\n        final Sequence sequence3 = new CountDownLatchSequence(8L, latch);\n\n        final SequenceBarrier sequenceBarrier =\n            ringBuffer.newBarrier(sequence1, sequence2, sequence3);\n\n        Thread t = new Thread(\n                () -> assertThrows(AlertException.class, () ->\n                        sequenceBarrier.waitFor(expectedNumberMessages - 1)));\n\n        t.start();\n        latch.await(3, TimeUnit.SECONDS);\n        sequenceBarrier.alert();\n        t.join();\n    }\n\n    @Test\n    public void shouldWaitForWorkCompleteWhereCompleteWorkThresholdIsBehind() throws Exception\n    {\n        long expectedNumberMessages = 10;\n        fillRingBuffer(expectedNumberMessages);\n\n        final DummyEventProcessor[] eventProcessors = new DummyEventProcessor[3];\n        for (int i = 0, size = eventProcessors.length; i < size; i++)\n        {\n            eventProcessors[i] = new DummyEventProcessor();\n            eventProcessors[i].setSequence(expectedNumberMessages - 2);\n        }\n\n        final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(Util.getSequencesFor(eventProcessors));\n\n        Runnable runnable = () ->\n        {\n            for (DummyEventProcessor stubWorker : eventProcessors)\n            {\n                stubWorker.setSequence(stubWorker.getSequence().get() + 1L);\n            }\n        };\n\n        Thread thread = new Thread(runnable);\n        thread.start();\n        thread.join();\n\n        long expectedWorkSequence = expectedNumberMessages - 1;\n        long completedWorkSequence = sequenceBarrier.waitFor(expectedWorkSequence);\n        assertTrue(completedWorkSequence >= expectedWorkSequence);\n    }\n\n    @Test\n    public void shouldSetAndClearAlertStatus()\n    {\n        SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n\n        assertFalse(sequenceBarrier.isAlerted());\n\n        sequenceBarrier.alert();\n        assertTrue(sequenceBarrier.isAlerted());\n\n        sequenceBarrier.clearAlert();\n        assertFalse(sequenceBarrier.isAlerted());\n    }\n\n    private void fillRingBuffer(final long expectedNumberMessages) throws InterruptedException\n    {\n        for (long i = 0; i < expectedNumberMessages; i++)\n        {\n            long sequence = ringBuffer.next();\n            StubEvent event = ringBuffer.get(sequence);\n            event.setValue((int) i);\n            ringBuffer.publish(sequence);\n        }\n    }\n\n    private static final class CountDownLatchSequence extends Sequence\n    {\n        private final CountDownLatch latch;\n\n        private CountDownLatchSequence(final long initialValue, final CountDownLatch latch)\n        {\n            super(initialValue);\n            this.latch = latch;\n        }\n\n        @Override\n        public long get()\n        {\n            latch.countDown();\n            return super.get();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/SequenceGroupTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.TestEvent;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\npublic final class SequenceGroupTest\n{\n    @Test\n    public void shouldReturnMaxSequenceWhenEmptyGroup()\n    {\n        final SequenceGroup sequenceGroup = new SequenceGroup();\n        assertEquals(Long.MAX_VALUE, sequenceGroup.get());\n    }\n\n    @Test\n    public void shouldAddOneSequenceToGroup()\n    {\n        final Sequence sequence = new Sequence(7L);\n        final SequenceGroup sequenceGroup = new SequenceGroup();\n\n        sequenceGroup.add(sequence);\n\n        assertEquals(sequence.get(), sequenceGroup.get());\n    }\n\n    @Test\n    public void shouldNotFailIfTryingToRemoveNotExistingSequence() throws Exception\n    {\n        SequenceGroup group = new SequenceGroup();\n        group.add(new Sequence());\n        group.add(new Sequence());\n        group.remove(new Sequence());\n    }\n\n    @Test\n    public void shouldReportTheMinimumSequenceForGroupOfTwo()\n    {\n        final Sequence sequenceThree = new Sequence(3L);\n        final Sequence sequenceSeven = new Sequence(7L);\n        final SequenceGroup sequenceGroup = new SequenceGroup();\n\n        sequenceGroup.add(sequenceSeven);\n        sequenceGroup.add(sequenceThree);\n\n        assertEquals(sequenceThree.get(), sequenceGroup.get());\n    }\n\n    @Test\n    public void shouldReportSizeOfGroup()\n    {\n        final SequenceGroup sequenceGroup = new SequenceGroup();\n        sequenceGroup.add(new Sequence());\n        sequenceGroup.add(new Sequence());\n        sequenceGroup.add(new Sequence());\n\n        assertEquals(3, sequenceGroup.size());\n    }\n\n    @Test\n    public void shouldRemoveSequenceFromGroup()\n    {\n        final Sequence sequenceThree = new Sequence(3L);\n        final Sequence sequenceSeven = new Sequence(7L);\n        final SequenceGroup sequenceGroup = new SequenceGroup();\n\n        sequenceGroup.add(sequenceSeven);\n        sequenceGroup.add(sequenceThree);\n\n        assertEquals(sequenceThree.get(), sequenceGroup.get());\n\n        assertTrue(sequenceGroup.remove(sequenceThree));\n        assertEquals(sequenceSeven.get(), sequenceGroup.get());\n        assertEquals(1, sequenceGroup.size());\n    }\n\n    @Test\n    public void shouldRemoveSequenceFromGroupWhereItBeenAddedMultipleTimes()\n    {\n        final Sequence sequenceThree = new Sequence(3L);\n        final Sequence sequenceSeven = new Sequence(7L);\n        final SequenceGroup sequenceGroup = new SequenceGroup();\n\n        sequenceGroup.add(sequenceThree);\n        sequenceGroup.add(sequenceSeven);\n        sequenceGroup.add(sequenceThree);\n\n        assertEquals(sequenceThree.get(), sequenceGroup.get());\n\n        assertTrue(sequenceGroup.remove(sequenceThree));\n        assertEquals(sequenceSeven.get(), sequenceGroup.get());\n        assertEquals(1, sequenceGroup.size());\n    }\n\n    @Test\n    public void shouldSetGroupSequenceToSameValue()\n    {\n        final Sequence sequenceThree = new Sequence(3L);\n        final Sequence sequenceSeven = new Sequence(7L);\n        final SequenceGroup sequenceGroup = new SequenceGroup();\n\n        sequenceGroup.add(sequenceSeven);\n        sequenceGroup.add(sequenceThree);\n\n        final long expectedSequence = 11L;\n        sequenceGroup.set(expectedSequence);\n\n        assertEquals(expectedSequence, sequenceThree.get());\n        assertEquals(expectedSequence, sequenceSeven.get());\n    }\n\n    @Test\n    public void shouldAddWhileRunning() throws Exception\n    {\n        RingBuffer<TestEvent> ringBuffer = RingBuffer.createSingleProducer(TestEvent.EVENT_FACTORY, 32);\n        final Sequence sequenceThree = new Sequence(3L);\n        final Sequence sequenceSeven = new Sequence(7L);\n        final SequenceGroup sequenceGroup = new SequenceGroup();\n        sequenceGroup.add(sequenceSeven);\n\n        for (int i = 0; i < 11; i++)\n        {\n            ringBuffer.publish(ringBuffer.next());\n        }\n\n        sequenceGroup.addWhileRunning(ringBuffer, sequenceThree);\n        assertThat(sequenceThree.get(), is(10L));\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/SequenceReportingCallbackTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.StubEvent;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.CountDownLatch;\n\nimport static com.lmax.disruptor.RingBuffer.createMultiProducer;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\npublic class SequenceReportingCallbackTest\n{\n    private final CountDownLatch callbackLatch = new CountDownLatch(1);\n    private final CountDownLatch onEndOfBatchLatch = new CountDownLatch(1);\n\n    @Test\n    public void shouldReportProgressByUpdatingSequenceViaCallback()\n        throws Exception\n    {\n        final RingBuffer<StubEvent> ringBuffer = createMultiProducer(StubEvent.EVENT_FACTORY, 16);\n        final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();\n        final EventHandler<StubEvent> handler = new TestSequenceReportingEventHandler();\n        final BatchEventProcessor<StubEvent> batchEventProcessor = new BatchEventProcessorBuilder().build(\n                ringBuffer, sequenceBarrier, handler);\n        ringBuffer.addGatingSequences(batchEventProcessor.getSequence());\n\n        Thread thread = new Thread(batchEventProcessor);\n        thread.setDaemon(true);\n        thread.start();\n\n        assertEquals(-1L, batchEventProcessor.getSequence().get());\n        ringBuffer.publish(ringBuffer.next());\n\n        callbackLatch.await();\n        assertEquals(0L, batchEventProcessor.getSequence().get());\n\n        onEndOfBatchLatch.countDown();\n        assertEquals(0L, batchEventProcessor.getSequence().get());\n\n        batchEventProcessor.halt();\n        thread.join();\n    }\n\n    private class TestSequenceReportingEventHandler implements EventHandler<StubEvent>\n    {\n        private Sequence sequenceCallback;\n\n        @Override\n        public void setSequenceCallback(final Sequence sequenceTrackerCallback)\n        {\n            this.sequenceCallback = sequenceTrackerCallback;\n        }\n\n        @Override\n        public void onEvent(final StubEvent event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            sequenceCallback.set(sequence);\n            callbackLatch.countDown();\n\n            if (endOfBatch)\n            {\n                onEndOfBatchLatch.await();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/SequenceTest.java",
    "content": "package com.lmax.disruptor;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass SequenceTest\n{\n    @Test\n    void shouldReturnChangedValueAfterAddAndGet()\n    {\n        final Sequence sequence = new Sequence(0);\n\n        assertEquals(10, sequence.addAndGet(10));\n        assertEquals(10, sequence.get());\n    }\n\n    @Test\n    void shouldReturnIncrementedValueAfterIncrementAndGet()\n    {\n        final Sequence sequence = new Sequence(0);\n\n        assertEquals(1, sequence.incrementAndGet());\n        assertEquals(1, sequence.get());\n    }\n\n    @Test\n    void shouldReturnPreviousValueAfterGetAndAdd()\n    {\n        final Sequence sequence = new Sequence(0);\n\n        assertEquals(0, sequence.getAndAdd(1));\n        assertEquals(1, sequence.get());\n    }\n}"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/SequencerTest.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.dsl.ProducerType;\nimport com.lmax.disruptor.support.DummyWaitStrategy;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.stream.Stream;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.params.provider.Arguments.arguments;\n\npublic class SequencerTest\n{\n    private static final int BUFFER_SIZE = 16;\n    private final ExecutorService executor = Executors.newSingleThreadExecutor(DaemonThreadFactory.INSTANCE);\n    private final Sequence gatingSequence = new Sequence();\n\n    private static Stream<Arguments> sequencerGenerator()\n    {\n        return Stream.of(\n                arguments(newProducer(ProducerType.SINGLE, new BlockingWaitStrategy())),\n                arguments(newProducer(ProducerType.MULTI, new BlockingWaitStrategy()))\n        );\n    }\n\n    private static Stream<Arguments> producerTypeGenerator()\n    {\n        return Stream.of(arguments(ProducerType.SINGLE), arguments(ProducerType.MULTI));\n    }\n\n    private static Sequencer newProducer(final ProducerType producerType, final WaitStrategy waitStrategy)\n    {\n        switch (producerType)\n        {\n            case SINGLE:\n                return new SingleProducerSequencer(BUFFER_SIZE, waitStrategy);\n            case MULTI:\n                return new MultiProducerSequencer(BUFFER_SIZE, waitStrategy);\n            default:\n                throw new IllegalStateException(producerType.toString());\n        }\n    }\n\n    @Test\n    public void shouldThrowAssertionErrorIfTwoThreadsPublishToSingleProducer() throws InterruptedException\n    {\n        Sequencer sequencer = new SingleProducerSequencer(BUFFER_SIZE, new BlockingWaitStrategy());\n        Thread otherThread  = new Thread(sequencer::next);\n        otherThread.start();\n        otherThread.join();\n\n        assertThrows(AssertionError.class, sequencer::next);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldStartWithInitialValue(final Sequencer sequencer)\n    {\n        assertEquals(0, sequencer.next());\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldBatchClaim(final Sequencer sequencer)\n    {\n        assertEquals(3, sequencer.next(4));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldIndicateHasAvailableCapacity(final Sequencer sequencer)\n    {\n        sequencer.addGatingSequences(gatingSequence);\n\n        assertTrue(sequencer.hasAvailableCapacity(1));\n        assertTrue(sequencer.hasAvailableCapacity(BUFFER_SIZE));\n        assertFalse(sequencer.hasAvailableCapacity(BUFFER_SIZE + 1));\n\n        sequencer.publish(sequencer.next());\n\n        assertTrue(sequencer.hasAvailableCapacity(BUFFER_SIZE - 1));\n        assertFalse(sequencer.hasAvailableCapacity(BUFFER_SIZE));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldIndicateNoAvailableCapacity(final Sequencer sequencer)\n    {\n        sequencer.addGatingSequences(gatingSequence);\n        long sequence = sequencer.next(BUFFER_SIZE);\n        sequencer.publish(sequence - (BUFFER_SIZE - 1), sequence);\n\n        assertFalse(sequencer.hasAvailableCapacity(1));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldHoldUpPublisherWhenBufferIsFull(final Sequencer sequencer)\n        throws InterruptedException\n    {\n        sequencer.addGatingSequences(gatingSequence);\n\n        final CountDownLatch waitingLatch = new CountDownLatch(1);\n        final CountDownLatch doneLatch = new CountDownLatch(1);\n\n        final long expectedFullSequence = Sequencer.INITIAL_CURSOR_VALUE + sequencer.getBufferSize();\n\n        executor.submit(\n                () ->\n                {\n                    long sequence = sequencer.next(BUFFER_SIZE);\n                    sequencer.publish(sequence - (BUFFER_SIZE - 1), sequence);\n\n                    assertThat(\n                            sequencer.getHighestPublishedSequence(Sequencer.INITIAL_CURSOR_VALUE + 1, sequencer.getCursor()),\n                            is(expectedFullSequence));\n\n                    waitingLatch.countDown();\n\n                    long next = sequencer.next();\n                    sequencer.publish(next);\n\n                    doneLatch.countDown();\n                });\n\n        waitingLatch.await();\n        assertThat(\n            sequencer.getHighestPublishedSequence(expectedFullSequence, sequencer.getCursor()),\n            is(expectedFullSequence));\n\n        gatingSequence.set(Sequencer.INITIAL_CURSOR_VALUE + 1L);\n\n        doneLatch.await();\n        assertThat(sequencer.getHighestPublishedSequence(expectedFullSequence, sequencer.getCursor()), is(expectedFullSequence + 1L));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldThrowInsufficientCapacityExceptionWhenSequencerIsFull(final Sequencer sequencer) throws Exception\n    {\n        assertThrows(InsufficientCapacityException.class, () ->\n        {\n            sequencer.addGatingSequences(gatingSequence);\n            for (int i = 0; i < BUFFER_SIZE; i++)\n            {\n                sequencer.next();\n            }\n            sequencer.tryNext();\n        });\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldCalculateRemainingCapacity(final Sequencer sequencer) throws Exception\n    {\n        sequencer.addGatingSequences(gatingSequence);\n\n        assertThat(sequencer.remainingCapacity(), is((long) BUFFER_SIZE));\n        for (int i = 1; i < BUFFER_SIZE; i++)\n        {\n            sequencer.next();\n            assertThat(sequencer.remainingCapacity(), is((long) BUFFER_SIZE - i));\n        }\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldNotBeAvailableUntilPublished(final Sequencer sequencer) throws Exception\n    {\n        long next = sequencer.next(6);\n\n        for (int i = 0; i <= 5; i++)\n        {\n            assertThat(sequencer.isAvailable(i), is(false));\n        }\n\n        sequencer.publish(next - (6 - 1), next);\n\n        for (int i = 0; i <= 5; i++)\n        {\n            assertThat(sequencer.isAvailable(i), is(true));\n        }\n\n        assertThat(sequencer.isAvailable(6), is(false));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"producerTypeGenerator\")\n    public void shouldNotifyWaitStrategyOnPublish(final ProducerType producerType) throws Exception\n    {\n        final DummyWaitStrategy waitStrategy = new DummyWaitStrategy();\n        final Sequenced sequencer = newProducer(producerType, waitStrategy);\n\n        sequencer.publish(sequencer.next());\n\n        assertThat(waitStrategy.signalAllWhenBlockingCalls, is(1));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"producerTypeGenerator\")\n    public void shouldNotifyWaitStrategyOnPublishBatch(final ProducerType producerType) throws Exception\n    {\n        final DummyWaitStrategy waitStrategy = new DummyWaitStrategy();\n        final Sequenced sequencer = newProducer(producerType, waitStrategy);\n\n        long next = sequencer.next(4);\n        sequencer.publish(next - (4 - 1), next);\n\n        assertThat(waitStrategy.signalAllWhenBlockingCalls, is(1));\n    }\n\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldWaitOnPublication(final Sequencer sequencer) throws Exception\n    {\n        SequenceBarrier barrier = sequencer.newBarrier();\n\n        long next = sequencer.next(10);\n        long lo = next - (10 - 1);\n        long mid = next - 5;\n\n        for (long l = lo; l < mid; l++)\n        {\n            sequencer.publish(l);\n        }\n\n        assertThat(barrier.waitFor(-1), is(mid - 1));\n\n        for (long l = mid; l <= next; l++)\n        {\n            sequencer.publish(l);\n        }\n\n        assertThat(barrier.waitFor(-1), is(next));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldTryNext(final Sequencer sequencer) throws Exception\n    {\n        sequencer.addGatingSequences(gatingSequence);\n\n        for (int i = 0; i < BUFFER_SIZE; i++)\n        {\n            sequencer.publish(sequencer.tryNext());\n        }\n\n        assertThrows(InsufficientCapacityException.class, sequencer::tryNext);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldClaimSpecificSequence(final Sequencer sequencer) throws Exception\n    {\n        long sequence = 14L;\n\n        sequencer.claim(sequence);\n        sequencer.publish(sequence);\n        assertThat(sequencer.next(), is(sequence + 1));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldNotAllowBulkNextLessThanZero(final Sequencer sequencer) throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () -> sequencer.next(-1));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldNotAllowBulkNextOfZero(final Sequencer sequencer) throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () -> sequencer.next(0));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldNotAllowBulkTryNextLessThanZero(final Sequencer sequencer) throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () -> sequencer.tryNext(-1));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    public void shouldNotAllowBulkTryNextOfZero(final Sequencer sequencer) throws Exception\n    {\n        assertThrows(IllegalArgumentException.class, () -> sequencer.tryNext(0));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    void sequencesBecomeAvailableAfterAPublish(final Sequencer sequencer)\n    {\n        final long seq = sequencer.next();\n        assertFalse(sequencer.isAvailable(seq));\n        sequencer.publish(seq);\n\n        assertTrue(sequencer.isAvailable(seq));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"sequencerGenerator\")\n    void sequencesBecomeUnavailableAfterWrapping(final Sequencer sequencer)\n    {\n        final long seq = sequencer.next();\n        sequencer.publish(seq);\n        assertTrue(sequencer.isAvailable(seq));\n\n        for (int i = 0; i < BUFFER_SIZE; i++)\n        {\n            sequencer.publish(sequencer.next());\n        }\n\n        assertFalse(sequencer.isAvailable(seq));\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/ShutdownOnFatalExceptionTest.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.dsl.Disruptor;\nimport com.lmax.disruptor.dsl.ProducerType;\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.Timeout;\n\nimport java.util.Random;\nimport java.util.concurrent.TimeUnit;\n\npublic class ShutdownOnFatalExceptionTest\n{\n\n    private final Random random = new Random();\n\n    private final FailingEventHandler eventHandler = new FailingEventHandler();\n\n    private Disruptor<byte[]> disruptor;\n\n    @SuppressWarnings(\"unchecked\")\n    @BeforeEach\n    public void setUp()\n    {\n        disruptor = new Disruptor<>(\n                new ByteArrayFactory(256), 1024, DaemonThreadFactory.INSTANCE, ProducerType.SINGLE,\n                new BlockingWaitStrategy());\n        disruptor.handleEventsWith(eventHandler);\n        disruptor.setDefaultExceptionHandler(new FatalExceptionHandler());\n    }\n\n    @Test\n    @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)\n    public void shouldShutdownGracefulEvenWithFatalExceptionHandler()\n    {\n        disruptor.start();\n\n        byte[] bytes;\n        for (int i = 1; i < 10; i++)\n        {\n            bytes = new byte[32];\n            random.nextBytes(bytes);\n            disruptor.publishEvent(new ByteArrayTranslator(bytes));\n        }\n    }\n\n    @AfterEach\n    public void tearDown()\n    {\n        disruptor.shutdown();\n    }\n\n    private static class ByteArrayTranslator implements EventTranslator<byte[]>\n    {\n\n        private final byte[] bytes;\n\n        ByteArrayTranslator(final byte[] bytes)\n        {\n            this.bytes = bytes;\n        }\n\n        @Override\n        public void translateTo(final byte[] event, final long sequence)\n        {\n            System.arraycopy(bytes, 0, event, 0, bytes.length);\n        }\n    }\n\n    private static class FailingEventHandler implements EventHandler<byte[]>\n    {\n        private int count = 0;\n\n        @Override\n        public void onEvent(final byte[] event, final long sequence, final boolean endOfBatch) throws Exception\n        {\n            // some logging\n            count++;\n            if (count == 3)\n            {\n                throw new IllegalStateException();\n            }\n        }\n    }\n\n    private static class ByteArrayFactory implements EventFactory<byte[]>\n    {\n        private int eventSize;\n\n        ByteArrayFactory(final int eventSize)\n        {\n            this.eventSize = eventSize;\n        }\n\n        @Override\n        public byte[] newInstance()\n        {\n            return new byte[eventSize];\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/SingleProducerSequencerTest.java",
    "content": "package com.lmax.disruptor;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.IsNot.not;\n\npublic class SingleProducerSequencerTest\n{\n    @Test\n    public void shouldNotUpdateCursorDuringHasAvailableCapacity() throws Exception\n    {\n        SingleProducerSequencer sequencer = new SingleProducerSequencer(16, new BusySpinWaitStrategy());\n\n        for (int i = 0; i < 32; i++)\n        {\n            long next = sequencer.next();\n            assertThat(sequencer.cursor.get(), not(next));\n\n            sequencer.hasAvailableCapacity(13);\n            assertThat(sequencer.cursor.get(), not(next));\n\n            sequencer.publish(next);\n        }\n    }\n}"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/SleepingWaitStrategyTest.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport org.junit.jupiter.api.Test;\n\nimport static com.lmax.disruptor.support.WaitStrategyTestUtil.assertWaitForWithDelayOf;\n\n\npublic class SleepingWaitStrategyTest\n{\n    @Test\n    public void shouldWaitForValue() throws Exception\n    {\n        assertWaitForWithDelayOf(50, new SleepingWaitStrategy());\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/TimeoutBlockingWaitStrategyTest.java",
    "content": "package com.lmax.disruptor;\n\nimport com.lmax.disruptor.support.DummySequenceBarrier;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n\npublic class TimeoutBlockingWaitStrategyTest\n{\n    @Test\n    public void shouldTimeoutWaitFor()\n    {\n        final SequenceBarrier sequenceBarrier = new DummySequenceBarrier();\n\n        long theTimeout = 500;\n        TimeoutBlockingWaitStrategy waitStrategy = new TimeoutBlockingWaitStrategy(theTimeout, TimeUnit.MILLISECONDS);\n        Sequence cursor = new Sequence(5);\n\n        long t0 = System.currentTimeMillis();\n\n        assertThrows(TimeoutException.class, () -> waitStrategy.waitFor(6, cursor, cursor, sequenceBarrier));\n\n        long t1 = System.currentTimeMillis();\n\n        long timeWaiting = t1 - t0;\n\n        assertTrue(timeWaiting >= theTimeout);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/YieldingWaitStrategyTest.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor;\n\nimport org.junit.jupiter.api.Test;\n\nimport static com.lmax.disruptor.support.WaitStrategyTestUtil.assertWaitForWithDelayOf;\n\npublic class YieldingWaitStrategyTest\n{\n\n    @Test\n    public void shouldWaitForValue() throws Exception\n    {\n        assertWaitForWithDelayOf(50, new YieldingWaitStrategy());\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/alternatives/MultiProducerSequencerUnsafe.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.alternatives;\n\nimport com.lmax.disruptor.AbstractSequencer;\nimport com.lmax.disruptor.InsufficientCapacityException;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.Sequencer;\nimport com.lmax.disruptor.WaitStrategy;\nimport com.lmax.disruptor.util.UnsafeAccess;\nimport com.lmax.disruptor.util.Util;\nimport sun.misc.Unsafe;\n\nimport java.util.concurrent.locks.LockSupport;\n\n\n/**\n * Coordinator for claiming sequences for access to a data structure while tracking dependent {@link Sequence}s.\n * Suitable for use for sequencing across multiple publisher threads.</p>\n *\n * <p> * Note on {@link Sequencer#getCursor()}:  With this sequencer the cursor value is updated after the call\n * to {@link Sequencer#next()}, to determine the highest available sequence that can be read, then\n * {@link Sequencer#getHighestPublishedSequence(long, long)} should be used.</p>\n */\npublic final class MultiProducerSequencerUnsafe extends AbstractSequencer\n{\n    private static final Unsafe UNSAFE = UnsafeAccess.getUnsafe();\n    private static final long BASE = UNSAFE.arrayBaseOffset(int[].class);\n    private static final long SCALE = UNSAFE.arrayIndexScale(int[].class);\n\n    private final Sequence gatingSequenceCache = new Sequence(Sequencer.INITIAL_CURSOR_VALUE);\n\n    // availableBuffer tracks the state of each ringbuffer slot\n    // see below for more details on the approach\n    private final int[] availableBuffer;\n    private final int indexMask;\n    private final int indexShift;\n\n    /**\n     * Construct a Sequencer with the selected wait strategy and buffer size.\n     *\n     * @param bufferSize   the size of the buffer that this will sequence over.\n     * @param waitStrategy for those waiting on sequences.\n     */\n    public MultiProducerSequencerUnsafe(final int bufferSize, final WaitStrategy waitStrategy)\n    {\n        super(bufferSize, waitStrategy);\n        availableBuffer = new int[bufferSize];\n        indexMask = bufferSize - 1;\n        indexShift = Util.log2(bufferSize);\n        initialiseAvailableBuffer();\n    }\n\n    /**\n     * @see Sequencer#hasAvailableCapacity(int)\n     */\n    @Override\n    public boolean hasAvailableCapacity(final int requiredCapacity)\n    {\n        return hasAvailableCapacity(gatingSequences, requiredCapacity, cursor.get());\n    }\n\n    private boolean hasAvailableCapacity(final Sequence[] gatingSequences, final int requiredCapacity, final long cursorValue)\n    {\n        long wrapPoint = (cursorValue + requiredCapacity) - bufferSize;\n        long cachedGatingSequence = gatingSequenceCache.get();\n\n        if (wrapPoint > cachedGatingSequence || cachedGatingSequence > cursorValue)\n        {\n            long minSequence = Util.getMinimumSequence(gatingSequences, cursorValue);\n            gatingSequenceCache.set(minSequence);\n\n            if (wrapPoint > minSequence)\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * @see Sequencer#claim(long)\n     */\n    @Override\n    public void claim(final long sequence)\n    {\n        cursor.set(sequence);\n    }\n\n    /**\n     * @see Sequencer#next()\n     */\n    @Override\n    public long next()\n    {\n        return next(1);\n    }\n\n    /**\n     * @see Sequencer#next(int)\n     */\n    @Override\n    public long next(final int n)\n    {\n        if (n < 1 || n > bufferSize)\n        {\n            throw new IllegalArgumentException(\"n must be > 0 and < bufferSize\");\n        }\n\n        long current;\n        long next;\n\n        do\n        {\n            current = cursor.get();\n            next = current + n;\n\n            long wrapPoint = next - bufferSize;\n            long cachedGatingSequence = gatingSequenceCache.get();\n\n            if (wrapPoint > cachedGatingSequence || cachedGatingSequence > current)\n            {\n                long gatingSequence = Util.getMinimumSequence(gatingSequences, current);\n\n                if (wrapPoint > gatingSequence)\n                {\n                    LockSupport.parkNanos(1); // TODO, should we spin based on the wait strategy?\n                    continue;\n                }\n\n                gatingSequenceCache.set(gatingSequence);\n            }\n            else if (cursor.compareAndSet(current, next))\n            {\n                break;\n            }\n        }\n        while (true);\n\n        return next;\n    }\n\n    /**\n     * @see Sequencer#tryNext()\n     */\n    @Override\n    public long tryNext() throws InsufficientCapacityException\n    {\n        return tryNext(1);\n    }\n\n    /**\n     * @see Sequencer#tryNext(int)\n     */\n    @Override\n    public long tryNext(final int n) throws InsufficientCapacityException\n    {\n        if (n < 1)\n        {\n            throw new IllegalArgumentException(\"n must be > 0\");\n        }\n\n        long current;\n        long next;\n\n        do\n        {\n            current = cursor.get();\n            next = current + n;\n\n            if (!hasAvailableCapacity(gatingSequences, n, current))\n            {\n                throw InsufficientCapacityException.INSTANCE;\n            }\n        }\n        while (!cursor.compareAndSet(current, next));\n\n        return next;\n    }\n\n    /**\n     * @see Sequencer#remainingCapacity()\n     */\n    @Override\n    public long remainingCapacity()\n    {\n        long consumed = Util.getMinimumSequence(gatingSequences, cursor.get());\n        long produced = cursor.get();\n        return getBufferSize() - (produced - consumed);\n    }\n\n    private void initialiseAvailableBuffer()\n    {\n        for (int i = availableBuffer.length - 1; i != 0; i--)\n        {\n            setAvailableBufferValue(i, -1);\n        }\n\n        setAvailableBufferValue(0, -1);\n    }\n\n    /**\n     * @see Sequencer#publish(long)\n     */\n    @Override\n    public void publish(final long sequence)\n    {\n        setAvailable(sequence);\n        waitStrategy.signalAllWhenBlocking();\n    }\n\n    /**\n     * @see Sequencer#publish(long, long)\n     */\n    @Override\n    public void publish(final long lo, final long hi)\n    {\n        for (long l = lo; l <= hi; l++)\n        {\n            setAvailable(l);\n        }\n        waitStrategy.signalAllWhenBlocking();\n    }\n\n    /**\n     * The below methods work on the availableBuffer flag.\n     *\n     * <p>The prime reason is to avoid a shared sequence object between publisher threads.\n     * (Keeping single pointers tracking start and end would require coordination\n     * between the threads).\n     *\n     * <p>--  Firstly we have the constraint that the delta between the cursor and minimum\n     * gating sequence will never be larger than the buffer size (the code in\n     * next/tryNext in the Sequence takes care of that).\n     * -- Given that; take the sequence value and mask off the lower portion of the\n     * sequence as the index into the buffer (indexMask). (aka modulo operator)\n     * -- The upper portion of the sequence becomes the value to check for availability.\n     * ie: it tells us how many times around the ring buffer we've been (aka division)\n     * -- Because we can't wrap without the gating sequences moving forward (i.e. the\n     * minimum gating sequence is effectively our last available position in the\n     * buffer), when we have new data and successfully claimed a slot we can simply\n     * write over the top.\n     */\n    private void setAvailable(final long sequence)\n    {\n        setAvailableBufferValue(calculateIndex(sequence), calculateAvailabilityFlag(sequence));\n    }\n\n    private void setAvailableBufferValue(final int index, final int flag)\n    {\n        long bufferAddress = (index * SCALE) + BASE;\n        UNSAFE.putOrderedInt(availableBuffer, bufferAddress, flag);\n    }\n\n    /**\n     * @see Sequencer#isAvailable(long)\n     */\n    @Override\n    public boolean isAvailable(final long sequence)\n    {\n        int index = calculateIndex(sequence);\n        int flag = calculateAvailabilityFlag(sequence);\n        long bufferAddress = (index * SCALE) + BASE;\n        return UNSAFE.getIntVolatile(availableBuffer, bufferAddress) == flag;\n    }\n\n    @Override\n    public long getHighestPublishedSequence(final long lowerBound, final long availableSequence)\n    {\n        for (long sequence = lowerBound; sequence <= availableSequence; sequence++)\n        {\n            if (!isAvailable(sequence))\n            {\n                return sequence - 1;\n            }\n        }\n\n        return availableSequence;\n    }\n\n    private int calculateAvailabilityFlag(final long sequence)\n    {\n        return (int) (sequence >>> indexShift);\n    }\n\n    private int calculateIndex(final long sequence)\n    {\n        return ((int) sequence) & indexMask;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/alternatives/MultiProducerSequencerVarHandle.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.alternatives;\n\nimport com.lmax.disruptor.AbstractSequencer;\nimport com.lmax.disruptor.InsufficientCapacityException;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.Sequencer;\nimport com.lmax.disruptor.WaitStrategy;\nimport com.lmax.disruptor.util.Util;\n\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.VarHandle;\nimport java.util.concurrent.locks.LockSupport;\n\n\n/**\n * Coordinator for claiming sequences for access to a data structure while tracking dependent {@link Sequence}s.\n * Suitable for use for sequencing across multiple publisher threads.</p>\n *\n * <p> * Note on {@link Sequencer#getCursor()}:  With this sequencer the cursor value is updated after the call\n * to {@link Sequencer#next()}, to determine the highest available sequence that can be read, then\n * {@link Sequencer#getHighestPublishedSequence(long, long)} should be used.</p>\n */\npublic final class MultiProducerSequencerVarHandle extends AbstractSequencer\n{\n    private static final VarHandle AVAILABLE_ARRAY = MethodHandles.arrayElementVarHandle(int[].class);\n\n    private final Sequence gatingSequenceCache = new Sequence(Sequencer.INITIAL_CURSOR_VALUE);\n\n    // availableBuffer tracks the state of each ringbuffer slot\n    // see below for more details on the approach\n    private final int[] availableBuffer;\n    private final int indexMask;\n    private final int indexShift;\n\n    /**\n     * Construct a Sequencer with the selected wait strategy and buffer size.\n     *\n     * @param bufferSize   the size of the buffer that this will sequence over.\n     * @param waitStrategy for those waiting on sequences.\n     */\n    public MultiProducerSequencerVarHandle(final int bufferSize, final WaitStrategy waitStrategy)\n    {\n        super(bufferSize, waitStrategy);\n        availableBuffer = new int[bufferSize];\n        indexMask = bufferSize - 1;\n        indexShift = Util.log2(bufferSize);\n        initialiseAvailableBuffer();\n    }\n\n    /**\n     * @see Sequencer#hasAvailableCapacity(int)\n     */\n    @Override\n    public boolean hasAvailableCapacity(final int requiredCapacity)\n    {\n        return hasAvailableCapacity(gatingSequences, requiredCapacity, cursor.get());\n    }\n\n    private boolean hasAvailableCapacity(final Sequence[] gatingSequences, final int requiredCapacity, final long cursorValue)\n    {\n        long wrapPoint = (cursorValue + requiredCapacity) - bufferSize;\n        long cachedGatingSequence = gatingSequenceCache.get();\n\n        if (wrapPoint > cachedGatingSequence || cachedGatingSequence > cursorValue)\n        {\n            long minSequence = Util.getMinimumSequence(gatingSequences, cursorValue);\n            gatingSequenceCache.set(minSequence);\n\n            if (wrapPoint > minSequence)\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * @see Sequencer#claim(long)\n     */\n    @Override\n    public void claim(final long sequence)\n    {\n        cursor.set(sequence);\n    }\n\n    /**\n     * @see Sequencer#next()\n     */\n    @Override\n    public long next()\n    {\n        return next(1);\n    }\n\n    /**\n     * @see Sequencer#next(int)\n     */\n    @Override\n    public long next(final int n)\n    {\n        if (n < 1 || n > bufferSize)\n        {\n            throw new IllegalArgumentException(\"n must be > 0 and < bufferSize\");\n        }\n\n        long current;\n        long next;\n\n        do\n        {\n            current = cursor.get();\n            next = current + n;\n\n            long wrapPoint = next - bufferSize;\n            long cachedGatingSequence = gatingSequenceCache.get();\n\n            if (wrapPoint > cachedGatingSequence || cachedGatingSequence > current)\n            {\n                long gatingSequence = Util.getMinimumSequence(gatingSequences, current);\n\n                if (wrapPoint > gatingSequence)\n                {\n                    LockSupport.parkNanos(1); // TODO, should we spin based on the wait strategy?\n                    continue;\n                }\n\n                gatingSequenceCache.set(gatingSequence);\n            }\n            else if (cursor.compareAndSet(current, next))\n            {\n                break;\n            }\n        }\n        while (true);\n\n        return next;\n    }\n\n    /**\n     * @see Sequencer#tryNext()\n     */\n    @Override\n    public long tryNext() throws InsufficientCapacityException\n    {\n        return tryNext(1);\n    }\n\n    /**\n     * @see Sequencer#tryNext(int)\n     */\n    @Override\n    public long tryNext(final int n) throws InsufficientCapacityException\n    {\n        if (n < 1)\n        {\n            throw new IllegalArgumentException(\"n must be > 0\");\n        }\n\n        long current;\n        long next;\n\n        do\n        {\n            current = cursor.get();\n            next = current + n;\n\n            if (!hasAvailableCapacity(gatingSequences, n, current))\n            {\n                throw InsufficientCapacityException.INSTANCE;\n            }\n        }\n        while (!cursor.compareAndSet(current, next));\n\n        return next;\n    }\n\n    /**\n     * @see Sequencer#remainingCapacity()\n     */\n    @Override\n    public long remainingCapacity()\n    {\n        long consumed = Util.getMinimumSequence(gatingSequences, cursor.get());\n        long produced = cursor.get();\n        return getBufferSize() - (produced - consumed);\n    }\n\n    private void initialiseAvailableBuffer()\n    {\n        for (int i = availableBuffer.length - 1; i != 0; i--)\n        {\n            setAvailableBufferValue(i, -1);\n        }\n\n        setAvailableBufferValue(0, -1);\n    }\n\n    /**\n     * @see Sequencer#publish(long)\n     */\n    @Override\n    public void publish(final long sequence)\n    {\n        setAvailable(sequence);\n        waitStrategy.signalAllWhenBlocking();\n    }\n\n    /**\n     * @see Sequencer#publish(long, long)\n     */\n    @Override\n    public void publish(final long lo, final long hi)\n    {\n        for (long l = lo; l <= hi; l++)\n        {\n            setAvailable(l);\n        }\n        waitStrategy.signalAllWhenBlocking();\n    }\n\n    /**\n     * The below methods work on the availableBuffer flag.\n     *\n     * <p>The prime reason is to avoid a shared sequence object between publisher threads.\n     * (Keeping single pointers tracking start and end would require coordination\n     * between the threads).\n     *\n     * <p>--  Firstly we have the constraint that the delta between the cursor and minimum\n     * gating sequence will never be larger than the buffer size (the code in\n     * next/tryNext in the Sequence takes care of that).\n     * -- Given that; take the sequence value and mask off the lower portion of the\n     * sequence as the index into the buffer (indexMask). (aka modulo operator)\n     * -- The upper portion of the sequence becomes the value to check for availability.\n     * ie: it tells us how many times around the ring buffer we've been (aka division)\n     * -- Because we can't wrap without the gating sequences moving forward (i.e. the\n     * minimum gating sequence is effectively our last available position in the\n     * buffer), when we have new data and successfully claimed a slot we can simply\n     * write over the top.\n     */\n    private void setAvailable(final long sequence)\n    {\n        setAvailableBufferValue(calculateIndex(sequence), calculateAvailabilityFlag(sequence));\n    }\n\n    private void setAvailableBufferValue(final int index, final int flag)\n    {\n        AVAILABLE_ARRAY.setRelease(availableBuffer, index, flag);\n    }\n\n    /**\n     * @see Sequencer#isAvailable(long)\n     */\n    @Override\n    public boolean isAvailable(final long sequence)\n    {\n        int index = calculateIndex(sequence);\n        int flag = calculateAvailabilityFlag(sequence);\n        return (int) AVAILABLE_ARRAY.getAcquire(availableBuffer, index) == flag;\n    }\n\n    @Override\n    public long getHighestPublishedSequence(final long lowerBound, final long availableSequence)\n    {\n        for (long sequence = lowerBound; sequence <= availableSequence; sequence++)\n        {\n            if (!isAvailable(sequence))\n            {\n                return sequence - 1;\n            }\n        }\n\n        return availableSequence;\n    }\n\n    private int calculateAvailabilityFlag(final long sequence)\n    {\n        return (int) (sequence >>> indexShift);\n    }\n\n    private int calculateIndex(final long sequence)\n    {\n        return ((int) sequence) & indexMask;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/alternatives/RingBufferArray.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.alternatives;\n\n\nimport com.lmax.disruptor.BlockingWaitStrategy;\nimport com.lmax.disruptor.Cursored;\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventPoller;\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.EventSequencer;\nimport com.lmax.disruptor.EventSink;\nimport com.lmax.disruptor.EventTranslator;\nimport com.lmax.disruptor.EventTranslatorOneArg;\nimport com.lmax.disruptor.EventTranslatorThreeArg;\nimport com.lmax.disruptor.EventTranslatorTwoArg;\nimport com.lmax.disruptor.EventTranslatorVararg;\nimport com.lmax.disruptor.InsufficientCapacityException;\nimport com.lmax.disruptor.MultiProducerSequencer;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.Sequencer;\nimport com.lmax.disruptor.SingleProducerSequencer;\nimport com.lmax.disruptor.WaitStrategy;\nimport com.lmax.disruptor.dsl.ProducerType;\n\nabstract class RingBufferPad\n{\n    protected byte\n        p10, p11, p12, p13, p14, p15, p16, p17,\n        p20, p21, p22, p23, p24, p25, p26, p27,\n        p30, p31, p32, p33, p34, p35, p36, p37,\n        p40, p41, p42, p43, p44, p45, p46, p47,\n        p50, p51, p52, p53, p54, p55, p56, p57,\n        p60, p61, p62, p63, p64, p65, p66, p67,\n        p70, p71, p72, p73, p74, p75, p76, p77;\n}\n\nabstract class RingBufferFieldsArray<E> extends RingBufferPad\n{\n    private static final int BUFFER_PAD = 32;\n\n    private final long indexMask;\n    private final E[] entries;\n    protected final int bufferSize;\n    protected final Sequencer sequencer;\n\n    @SuppressWarnings(\"unchecked\")\n    RingBufferFieldsArray(\n        final EventFactory<E> eventFactory,\n        final Sequencer sequencer)\n    {\n        this.sequencer = sequencer;\n        this.bufferSize = sequencer.getBufferSize();\n\n        if (bufferSize < 1)\n        {\n            throw new IllegalArgumentException(\"bufferSize must not be less than 1\");\n        }\n        if (Integer.bitCount(bufferSize) != 1)\n        {\n            throw new IllegalArgumentException(\"bufferSize must be a power of 2\");\n        }\n\n        this.indexMask = bufferSize - 1;\n        this.entries = (E[]) new Object[sequencer.getBufferSize() + 2 * BUFFER_PAD];\n        fill(eventFactory);\n    }\n\n    private void fill(final EventFactory<E> eventFactory)\n    {\n        for (int i = 0; i < bufferSize; i++)\n        {\n            entries[BUFFER_PAD + i] = eventFactory.newInstance();\n        }\n    }\n\n    protected final E elementAt(final long sequence)\n    {\n        return entries[BUFFER_PAD + (int) (sequence & indexMask)];\n    }\n}\n\n/**\n * Ring based store of reusable entries containing the data representing\n * an event being exchanged between event producer and {@link EventProcessor}s.\n *\n * @param <E> implementation storing the data for sharing during exchange or parallel coordination of an event.\n */\npublic final class RingBufferArray<E> extends RingBufferFieldsArray<E> implements Cursored, EventSequencer<E>, EventSink<E>\n{\n    /**\n     * The initial cursor value\n     */\n    public static final long INITIAL_CURSOR_VALUE = SequenceVarHandle.INITIAL_VALUE;\n    protected byte\n        p10, p11, p12, p13, p14, p15, p16, p17,\n        p20, p21, p22, p23, p24, p25, p26, p27,\n        p30, p31, p32, p33, p34, p35, p36, p37,\n        p40, p41, p42, p43, p44, p45, p46, p47,\n        p50, p51, p52, p53, p54, p55, p56, p57,\n        p60, p61, p62, p63, p64, p65, p66, p67,\n        p70, p71, p72, p73, p74, p75, p76, p77;\n\n    /**\n     * Construct a RingBuffer with the full option set.\n     *\n     * @param eventFactory to newInstance entries for filling the RingBuffer\n     * @param sequencer    sequencer to handle the ordering of events moving through the RingBuffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     */\n    public RingBufferArray(\n            final EventFactory<E> eventFactory,\n            final Sequencer sequencer)\n    {\n        super(eventFactory, sequencer);\n    }\n\n    /**\n     * Create a new multiple producer RingBuffer with the specified wait strategy.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory      used to create the events within the ring buffer.\n     * @param bufferSize   number of elements to create within the ring buffer.\n     * @param waitStrategy used to determine how to wait for new elements to become available.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     * @see MultiProducerSequencer\n     */\n    public static <E> RingBufferArray<E> createMultiProducer(\n        final EventFactory<E> factory,\n        final int bufferSize,\n        final WaitStrategy waitStrategy)\n    {\n        MultiProducerSequencer sequencer = new MultiProducerSequencer(bufferSize, waitStrategy);\n\n        return new RingBufferArray<>(factory, sequencer);\n    }\n\n    /**\n     * Create a new multiple producer RingBuffer using the default wait strategy  {@link BlockingWaitStrategy}.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory    used to create the events within the ring buffer.\n     * @param bufferSize number of elements to create within the ring buffer.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if <code>bufferSize</code> is less than 1 or not a power of 2\n     * @see MultiProducerSequencer\n     */\n    public static <E> RingBufferArray<E> createMultiProducer(final EventFactory<E> factory, final int bufferSize)\n    {\n        return createMultiProducer(factory, bufferSize, new BlockingWaitStrategy());\n    }\n\n    /**\n     * Create a new single producer RingBuffer with the specified wait strategy.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory      used to create the events within the ring buffer.\n     * @param bufferSize   number of elements to create within the ring buffer.\n     * @param waitStrategy used to determine how to wait for new elements to become available.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     * @see SingleProducerSequencer\n     */\n    public static <E> RingBufferArray<E> createSingleProducer(\n        final EventFactory<E> factory,\n        final int bufferSize,\n        final WaitStrategy waitStrategy)\n    {\n        SingleProducerSequencer sequencer = new SingleProducerSequencer(bufferSize, waitStrategy);\n\n        return new RingBufferArray<>(factory, sequencer);\n    }\n\n    /**\n     * Create a new single producer RingBuffer using the default wait strategy  {@link BlockingWaitStrategy}.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory    used to create the events within the ring buffer.\n     * @param bufferSize number of elements to create within the ring buffer.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if <code>bufferSize</code> is less than 1 or not a power of 2\n     * @see MultiProducerSequencer\n     */\n    public static <E> RingBufferArray<E> createSingleProducer(final EventFactory<E> factory, final int bufferSize)\n    {\n        return createSingleProducer(factory, bufferSize, new BlockingWaitStrategy());\n    }\n\n    /**\n     * Create a new Ring Buffer with the specified producer type (SINGLE or MULTI)\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param producerType producer type to use {@link ProducerType}.\n     * @param factory      used to create events within the ring buffer.\n     * @param bufferSize   number of elements to create within the ring buffer.\n     * @param waitStrategy used to determine how to wait for new elements to become available.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     */\n    public static <E> RingBufferArray<E> create(\n        final ProducerType producerType,\n        final EventFactory<E> factory,\n        final int bufferSize,\n        final WaitStrategy waitStrategy)\n    {\n        switch (producerType)\n        {\n            case SINGLE:\n                return createSingleProducer(factory, bufferSize, waitStrategy);\n            case MULTI:\n                return createMultiProducer(factory, bufferSize, waitStrategy);\n            default:\n                throw new IllegalStateException(producerType.toString());\n        }\n    }\n\n    /**\n     * <p>Get the event for a given sequence in the RingBuffer.</p>\n     *\n     * <p>This call has 2 uses.  Firstly use this call when publishing to a ring buffer.\n     * After calling {@link RingBufferArray#next()} use this call to get hold of the\n     * preallocated event to fill with data before calling {@link RingBufferArray#publish(long)}.</p>\n     *\n     * <p>Secondly use this call when consuming data from the ring buffer.  After calling\n     * {@link SequenceBarrier#waitFor(long)} call this method with any value greater than\n     * that your current consumer sequence and less than or equal to the value returned from\n     * the {@link SequenceBarrier#waitFor(long)} method.</p>\n     *\n     * @param sequence for the event\n     * @return the event for the given sequence\n     */\n    @Override\n    public E get(final long sequence)\n    {\n        return elementAt(sequence);\n    }\n\n    /**\n     * Increment and return the next sequence for the ring buffer.  Calls of this\n     * method should ensure that they always publish the sequence afterward.  E.g.\n     * <pre>\n     * long sequence = ringBuffer.next();\n     * try {\n     *     Event e = ringBuffer.get(sequence);\n     *     // Do some work with the event.\n     * } finally {\n     *     ringBuffer.publish(sequence);\n     * }\n     * </pre>\n     *\n     * @return The next sequence to publish to.\n     * @see RingBufferArray#publish(long)\n     * @see RingBufferArray#get(long)\n     */\n    @Override\n    public long next()\n    {\n        return sequencer.next();\n    }\n\n    /**\n     * The same functionality as {@link RingBufferArray#next()}, but allows the caller to claim\n     * the next n sequences.\n     *\n     * @param n number of slots to claim\n     * @return sequence number of the highest slot claimed\n     * @see Sequencer#next(int)\n     */\n    @Override\n    public long next(final int n)\n    {\n        return sequencer.next(n);\n    }\n\n    /**\n     * <p>Increment and return the next sequence for the ring buffer.  Calls of this\n     * method should ensure that they always publish the sequence afterward.  E.g.</p>\n     * <pre>\n     * long sequence = ringBuffer.next();\n     * try {\n     *     Event e = ringBuffer.get(sequence);\n     *     // Do some work with the event.\n     * } finally {\n     *     ringBuffer.publish(sequence);\n     * }\n     * </pre>\n     * <p>This method will not block if there is not space available in the ring\n     * buffer, instead it will throw an {@link InsufficientCapacityException}.</p>\n     *\n     * @return The next sequence to publish to.\n     * @throws InsufficientCapacityException if the necessary space in the ring buffer is not available\n     * @see RingBufferArray#publish(long)\n     * @see RingBufferArray#get(long)\n     */\n    @Override\n    public long tryNext() throws InsufficientCapacityException\n    {\n        return sequencer.tryNext();\n    }\n\n    /**\n     * The same functionality as {@link RingBufferArray#tryNext()}, but allows the caller to attempt\n     * to claim the next n sequences.\n     *\n     * @param n number of slots to claim\n     * @return sequence number of the highest slot claimed\n     * @throws InsufficientCapacityException if the necessary space in the ring buffer is not available\n     */\n    @Override\n    public long tryNext(final int n) throws InsufficientCapacityException\n    {\n        return sequencer.tryNext(n);\n    }\n\n    /**\n     * Resets the cursor to a specific value.  This can be applied at any time, but it is worth noting\n     * that it can cause a data race and should only be used in controlled circumstances.  E.g. during\n     * initialisation.\n     *\n     * @param sequence The sequence to reset too.\n     * @throws IllegalStateException If any gating sequences have already been specified.\n     */\n    @Deprecated\n    public void resetTo(final long sequence)\n    {\n        sequencer.claim(sequence);\n        sequencer.publish(sequence);\n    }\n\n    /**\n     * Sets the cursor to a specific sequence and returns the preallocated entry that is stored there.  This\n     * can cause a data race and should only be done in controlled circumstances, e.g. during initialisation.\n     *\n     * @param sequence The sequence to claim.\n     * @return The preallocated event.\n     */\n    public E claimAndGetPreallocated(final long sequence)\n    {\n        sequencer.claim(sequence);\n        return get(sequence);\n    }\n\n    /**\n     * Determines if the event for a given sequence is currently available.\n     *\n     * <p>Note that this does not guarantee that event will still be available\n     * on the next interaction with the RingBuffer. For example, it is not\n     * necessarily safe to write code like this:\n     *\n     * <pre>{@code\n     * if (ringBuffer.isAvailable(sequence))\n     * {\n     *     final E e = ringBuffer.get(sequence);\n     *     // ...do something with e\n     * }\n     * }</pre>\n     *\n     * <p>because there is a race between the reading thread and the writing thread.\n     *\n     * <p>This method will also return false when querying for sequences that are\n     * behind the ring buffer's wrap point.\n     *\n     * @param sequence The sequence to identify the entry.\n     * @return If the event published with the given sequence number is currently available.\n     */\n    public boolean isAvailable(final long sequence)\n    {\n        return sequencer.isAvailable(sequence);\n    }\n\n    /**\n     * Add the specified gating sequences to this instance of the Disruptor.  They will\n     * safely and atomically added to the list of gating sequences.\n     *\n     * @param gatingSequences The sequences to add.\n     */\n    public void addGatingSequences(final Sequence... gatingSequences)\n    {\n        sequencer.addGatingSequences(gatingSequences);\n    }\n\n    /**\n     * Get the minimum sequence value from all of the gating sequences\n     * added to this ringBuffer.\n     *\n     * @return The minimum gating sequence or the cursor sequence if\n     * no sequences have been added.\n     */\n    public long getMinimumGatingSequence()\n    {\n        return sequencer.getMinimumSequence();\n    }\n\n    /**\n     * Remove the specified sequence from this ringBuffer.\n     *\n     * @param sequence to be removed.\n     * @return <code>true</code> if this sequence was found, <code>false</code> otherwise.\n     */\n    public boolean removeGatingSequence(final Sequence sequence)\n    {\n        return sequencer.removeGatingSequence(sequence);\n    }\n\n    /**\n     * Create a new SequenceBarrier to be used by an EventProcessor to track which messages\n     * are available to be read from the ring buffer given a list of sequences to track.\n     *\n     * @param sequencesToTrack the additional sequences to track\n     * @return A sequence barrier that will track the specified sequences.\n     * @see SequenceBarrier\n     */\n    public SequenceBarrier newBarrier(final Sequence... sequencesToTrack)\n    {\n        return sequencer.newBarrier(sequencesToTrack);\n    }\n\n    /**\n     * Creates an event poller for this ring buffer gated on the supplied sequences.\n     *\n     * @param gatingSequences to be gated on.\n     * @return A poller that will gate on this ring buffer and the supplied sequences.\n     */\n    public EventPoller<E> newPoller(final Sequence... gatingSequences)\n    {\n        return sequencer.newPoller(this, gatingSequences);\n    }\n\n    /**\n     * Get the current cursor value for the ring buffer.  The actual value received\n     * will depend on the type of {@link Sequencer} that is being used.\n     *\n     * @see MultiProducerSequencer\n     * @see SingleProducerSequencer\n     */\n    @Override\n    public long getCursor()\n    {\n        return sequencer.getCursor();\n    }\n\n    /**\n     * The size of the buffer.\n     *\n     * @return size of buffer\n     */\n    @Override\n    public int getBufferSize()\n    {\n        return bufferSize;\n    }\n\n    /**\n     * Given specified <code>requiredCapacity</code> determines if that amount of space\n     * is available.  Note, you can not assume that if this method returns <code>true</code>\n     * that a call to {@link RingBufferArray#next()} will not block.  Especially true if this\n     * ring buffer is set up to handle multiple producers.\n     *\n     * @param requiredCapacity The capacity to check for.\n     * @return <code>true</code> If the specified <code>requiredCapacity</code> is available\n     * <code>false</code> if not.\n     */\n    @Override\n    public boolean hasAvailableCapacity(final int requiredCapacity)\n    {\n        return sequencer.hasAvailableCapacity(requiredCapacity);\n    }\n\n\n    /**\n     * @see EventSink#publishEvent(EventTranslator)\n     */\n    @Override\n    public void publishEvent(final EventTranslator<E> translator)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvent(EventTranslator)\n     */\n    @Override\n    public boolean tryPublishEvent(final EventTranslator<E> translator)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see EventSink#publishEvent(EventTranslatorOneArg, Object)\n     * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorOneArg, A)\n     */\n    @Override\n    public <A> void publishEvent(final EventTranslatorOneArg<E, A> translator, final A arg0)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, arg0);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvent(EventTranslatorOneArg, Object)\n     * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorOneArg, A)\n     */\n    @Override\n    public <A> boolean tryPublishEvent(final EventTranslatorOneArg<E, A> translator, final A arg0)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, arg0);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see EventSink#publishEvent(EventTranslatorTwoArg, Object, Object)\n     * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorTwoArg, A, B)\n     */\n    @Override\n    public <A, B> void publishEvent(final EventTranslatorTwoArg<E, A, B> translator, final A arg0, final B arg1)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, arg0, arg1);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvent(EventTranslatorTwoArg, Object, Object)\n     * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorTwoArg, A, B)\n     */\n    @Override\n    public <A, B> boolean tryPublishEvent(final EventTranslatorTwoArg<E, A, B> translator, final A arg0, final B arg1)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, arg0, arg1);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see EventSink#publishEvent(EventTranslatorThreeArg, Object, Object, Object)\n     * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorThreeArg, A, B, C)\n     */\n    @Override\n    public <A, B, C> void publishEvent(final EventTranslatorThreeArg<E, A, B, C> translator, final A arg0, final B arg1, final C arg2)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, arg0, arg1, arg2);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvent(EventTranslatorThreeArg, Object, Object, Object)\n     * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorThreeArg, A, B, C)\n     */\n    @Override\n    public <A, B, C> boolean tryPublishEvent(final EventTranslatorThreeArg<E, A, B, C> translator, final A arg0, final B arg1, final C arg2)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, arg0, arg1, arg2);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see EventSink#publishEvent(EventTranslatorVararg, Object...)\n     */\n    @Override\n    public void publishEvent(final EventTranslatorVararg<E> translator, final Object... args)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, args);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvent(EventTranslatorVararg, Object...)\n     */\n    @Override\n    public boolean tryPublishEvent(final EventTranslatorVararg<E> translator, final Object... args)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, args);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n\n    /**\n     * @see EventSink#publishEvents(EventTranslator[])\n     */\n    @Override\n    public void publishEvents(final EventTranslator<E>[] translators)\n    {\n        publishEvents(translators, 0, translators.length);\n    }\n\n    /**\n     * @see EventSink#publishEvents(EventTranslator[], int, int)\n     */\n    @Override\n    public void publishEvents(final EventTranslator<E>[] translators, final int batchStartsAt, final int batchSize)\n    {\n        checkBounds(translators, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translators, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvents(EventTranslator[])\n     */\n    @Override\n    public boolean tryPublishEvents(final EventTranslator<E>[] translators)\n    {\n        return tryPublishEvents(translators, 0, translators.length);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvents(EventTranslator[], int, int)\n     */\n    @Override\n    public boolean tryPublishEvents(final EventTranslator<E>[] translators, final int batchStartsAt, final int batchSize)\n    {\n        checkBounds(translators, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translators, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see EventSink#publishEvents(EventTranslatorOneArg, Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, A[])\n     */\n    @Override\n    public <A> void publishEvents(final EventTranslatorOneArg<E, A> translator, final A[] arg0)\n    {\n        publishEvents(translator, 0, arg0.length, arg0);\n    }\n\n    /**\n     * @see EventSink#publishEvents(EventTranslatorOneArg, int, int, Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, A[])\n     */\n    @Override\n    public <A> void publishEvents(final EventTranslatorOneArg<E, A> translator, final int batchStartsAt, final int batchSize, final A[] arg0)\n    {\n        checkBounds(arg0, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, arg0, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvents(EventTranslatorOneArg, Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, A[])\n     */\n    @Override\n    public <A> boolean tryPublishEvents(final EventTranslatorOneArg<E, A> translator, final A[] arg0)\n    {\n        return tryPublishEvents(translator, 0, arg0.length, arg0);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvents(EventTranslatorOneArg, int, int, Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, A[])\n     */\n    @Override\n    public <A> boolean tryPublishEvents(\n            final EventTranslatorOneArg<E, A> translator, final int batchStartsAt, final int batchSize, final A[] arg0)\n    {\n        checkBounds(arg0, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, arg0, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see EventSink#publishEvents(EventTranslatorTwoArg, Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, A[], B[])\n     */\n    @Override\n    public <A, B> void publishEvents(final EventTranslatorTwoArg<E, A, B> translator, final A[] arg0, final B[] arg1)\n    {\n        publishEvents(translator, 0, arg0.length, arg0, arg1);\n    }\n\n    /**\n     * @see EventSink#publishEvents(EventTranslatorTwoArg, int, int, Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, A[], B[])\n     */\n    @Override\n    public <A, B> void publishEvents(\n        final EventTranslatorTwoArg<E, A, B> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1)\n    {\n        checkBounds(arg0, arg1, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, arg0, arg1, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvents(EventTranslatorTwoArg, Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, A[], B[])\n     */\n    @Override\n    public <A, B> boolean tryPublishEvents(final EventTranslatorTwoArg<E, A, B> translator, final A[] arg0, final B[] arg1)\n    {\n        return tryPublishEvents(translator, 0, arg0.length, arg0, arg1);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvents(EventTranslatorTwoArg, int, int, Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, A[], B[])\n     */\n    @Override\n    public <A, B> boolean tryPublishEvents(\n        final EventTranslatorTwoArg<E, A, B> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1)\n    {\n        checkBounds(arg0, arg1, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, arg0, arg1, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see EventSink#publishEvents(EventTranslatorThreeArg, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> void publishEvents(final EventTranslatorThreeArg<E, A, B, C> translator, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        publishEvents(translator, 0, arg0.length, arg0, arg1, arg2);\n    }\n\n    /**\n     * @see EventSink#publishEvents(EventTranslatorThreeArg, int, int, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> void publishEvents(\n        final EventTranslatorThreeArg<E, A, B, C> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        checkBounds(arg0, arg1, arg2, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, arg0, arg1, arg2, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvents(EventTranslatorThreeArg, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> boolean tryPublishEvents(\n        final EventTranslatorThreeArg<E, A, B, C> translator, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        return tryPublishEvents(translator, 0, arg0.length, arg0, arg1, arg2);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvents(EventTranslatorThreeArg, int, int, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> boolean tryPublishEvents(\n        final EventTranslatorThreeArg<E, A, B, C> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        checkBounds(arg0, arg1, arg2, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, arg0, arg1, arg2, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see EventSink#publishEvents(EventTranslatorVararg, Object[][])\n     */\n    @Override\n    public void publishEvents(final EventTranslatorVararg<E> translator, final Object[]... args)\n    {\n        publishEvents(translator, 0, args.length, args);\n    }\n\n    /**\n     * @see EventSink#publishEvents(EventTranslatorVararg, int, int, Object[][])\n     */\n    @Override\n    public void publishEvents(final EventTranslatorVararg<E> translator, final int batchStartsAt, final int batchSize, final Object[]... args)\n    {\n        checkBounds(batchStartsAt, batchSize, args);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, batchStartsAt, batchSize, finalSequence, args);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvents(EventTranslatorVararg, Object[][])\n     */\n    @Override\n    public boolean tryPublishEvents(final EventTranslatorVararg<E> translator, final Object[]... args)\n    {\n        return tryPublishEvents(translator, 0, args.length, args);\n    }\n\n    /**\n     * @see EventSink#tryPublishEvents(EventTranslatorVararg, int, int, Object[][])\n     */\n    @Override\n    public boolean tryPublishEvents(\n        final EventTranslatorVararg<E> translator, final int batchStartsAt, final int batchSize, final Object[]... args)\n    {\n        checkBounds(args, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, batchStartsAt, batchSize, finalSequence, args);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * Publish the specified sequence.  This action marks this particular\n     * message as being available to be read.\n     *\n     * @param sequence the sequence to publish.\n     */\n    @Override\n    public void publish(final long sequence)\n    {\n        sequencer.publish(sequence);\n    }\n\n    /**\n     * Publish the specified sequences.  This action marks these particular\n     * messages as being available to be read.\n     *\n     * @param lo the lowest sequence number to be published\n     * @param hi the highest sequence number to be published\n     * @see Sequencer#next(int)\n     */\n    @Override\n    public void publish(final long lo, final long hi)\n    {\n        sequencer.publish(lo, hi);\n    }\n\n    /**\n     * Get the remaining capacity for this ringBuffer.\n     *\n     * @return The number of slots remaining.\n     */\n    @Override\n    public long remainingCapacity()\n    {\n        return sequencer.remainingCapacity();\n    }\n\n    private void checkBounds(final EventTranslator<E>[] translators, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(translators, batchStartsAt, batchSize);\n    }\n\n    private void checkBatchSizing(final int batchStartsAt, final int batchSize)\n    {\n        if (batchStartsAt < 0 || batchSize < 0)\n        {\n            throw new IllegalArgumentException(\"Both batchStartsAt and batchSize must be positive but got: batchStartsAt \" + batchStartsAt + \" and batchSize \" + batchSize);\n        }\n        else if (batchSize > bufferSize)\n        {\n            throw new IllegalArgumentException(\"The ring buffer cannot accommodate \" + batchSize + \" it only has space for \" + bufferSize + \" entities.\");\n        }\n    }\n\n    private <A> void checkBounds(final A[] arg0, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(arg0, batchStartsAt, batchSize);\n    }\n\n    private <A, B> void checkBounds(final A[] arg0, final B[] arg1, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(arg0, batchStartsAt, batchSize);\n        batchOverRuns(arg1, batchStartsAt, batchSize);\n    }\n\n    private <A, B, C> void checkBounds(\n        final A[] arg0, final B[] arg1, final C[] arg2, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(arg0, batchStartsAt, batchSize);\n        batchOverRuns(arg1, batchStartsAt, batchSize);\n        batchOverRuns(arg2, batchStartsAt, batchSize);\n    }\n\n    private void checkBounds(final int batchStartsAt, final int batchSize, final Object[][] args)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(args, batchStartsAt, batchSize);\n    }\n\n    private <A> void batchOverRuns(final A[] arg0, final int batchStartsAt, final int batchSize)\n    {\n        if (batchStartsAt + batchSize > arg0.length)\n        {\n            throw new IllegalArgumentException(\n                \"A batchSize of: \" + batchSize +\n                    \" with batchStatsAt of: \" + batchStartsAt +\n                    \" will overrun the available number of arguments: \" + (arg0.length - batchStartsAt));\n        }\n    }\n\n    private void translateAndPublish(final EventTranslator<E> translator, final long sequence)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private <A> void translateAndPublish(final EventTranslatorOneArg<E, A> translator, final long sequence, final A arg0)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, arg0);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private <A, B> void translateAndPublish(final EventTranslatorTwoArg<E, A, B> translator, final long sequence, final A arg0, final B arg1)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, arg0, arg1);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private <A, B, C> void translateAndPublish(\n        final EventTranslatorThreeArg<E, A, B, C> translator, final long sequence,\n        final A arg0, final B arg1, final C arg2)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, arg0, arg1, arg2);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private void translateAndPublish(final EventTranslatorVararg<E> translator, final long sequence, final Object... args)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, args);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private void translateAndPublishBatch(\n        final EventTranslator<E>[] translators, final int batchStartsAt,\n        final int batchSize, final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                final EventTranslator<E> translator = translators[i];\n                translator.translateTo(get(sequence), sequence++);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private <A> void translateAndPublishBatch(\n        final EventTranslatorOneArg<E, A> translator, final A[] arg0,\n        final int batchStartsAt, final int batchSize, final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, arg0[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private <A, B> void translateAndPublishBatch(\n        final EventTranslatorTwoArg<E, A, B> translator, final A[] arg0,\n        final B[] arg1, final int batchStartsAt, final int batchSize,\n        final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, arg0[i], arg1[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private <A, B, C> void translateAndPublishBatch(\n        final EventTranslatorThreeArg<E, A, B, C> translator,\n        final A[] arg0, final B[] arg1, final C[] arg2, final int batchStartsAt,\n        final int batchSize, final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, arg0[i], arg1[i], arg2[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private void translateAndPublishBatch(\n        final EventTranslatorVararg<E> translator, final int batchStartsAt,\n        final int batchSize, final long finalSequence, final Object[][] args)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, args[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"RingBuffer{\" +\n            \"bufferSize=\" + bufferSize +\n            \", sequencer=\" + sequencer +\n            \"}\";\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/alternatives/RingBufferUnsafe.java",
    "content": "package com.lmax.disruptor.alternatives;\n\nimport com.lmax.disruptor.BlockingWaitStrategy;\nimport com.lmax.disruptor.Cursored;\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventPoller;\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.EventSequencer;\nimport com.lmax.disruptor.EventSink;\nimport com.lmax.disruptor.EventTranslator;\nimport com.lmax.disruptor.EventTranslatorOneArg;\nimport com.lmax.disruptor.EventTranslatorThreeArg;\nimport com.lmax.disruptor.EventTranslatorTwoArg;\nimport com.lmax.disruptor.EventTranslatorVararg;\nimport com.lmax.disruptor.InsufficientCapacityException;\nimport com.lmax.disruptor.MultiProducerSequencer;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.Sequencer;\nimport com.lmax.disruptor.SingleProducerSequencer;\nimport com.lmax.disruptor.WaitStrategy;\nimport com.lmax.disruptor.dsl.ProducerType;\nimport com.lmax.disruptor.util.UnsafeAccess;\nimport sun.misc.Unsafe;\n\nabstract class RingBufferPadUnsafe\n{\n    protected byte\n            p10, p11, p12, p13, p14, p15, p16, p17,\n            p20, p21, p22, p23, p24, p25, p26, p27,\n            p30, p31, p32, p33, p34, p35, p36, p37,\n            p40, p41, p42, p43, p44, p45, p46, p47,\n            p50, p51, p52, p53, p54, p55, p56, p57,\n            p60, p61, p62, p63, p64, p65, p66, p67,\n            p70, p71, p72, p73, p74, p75, p76, p77;\n}\n\nabstract class RingBufferFieldsUnsafe<E> extends RingBufferPadUnsafe\n{\n    private static final int BUFFER_PAD;\n    private static final long REF_ARRAY_BASE;\n    private static final int REF_ELEMENT_SHIFT;\n    private static final Unsafe UNSAFE = UnsafeAccess.getUnsafe();\n\n    private static final int POINTER_SIZE_32_BIT = 4;\n    private static final int BITSHIFT_MULTIPLIER_FOUR = 2;\n    public static final int POINTER_SIZE_64_BIT = 8;\n    private static final int BITSHIFT_MULTIPLIER_EIGHT = 3;\n\n    private static final int BUFFER_PADDING_BYTES = 128;\n\n    static\n    {\n        final int scale = UNSAFE.arrayIndexScale(Object[].class);\n        if (POINTER_SIZE_32_BIT == scale)\n        {\n            REF_ELEMENT_SHIFT = BITSHIFT_MULTIPLIER_FOUR;\n        }\n        else if (POINTER_SIZE_64_BIT == scale)\n        {\n            REF_ELEMENT_SHIFT = BITSHIFT_MULTIPLIER_EIGHT;\n        }\n        else\n        {\n            throw new IllegalStateException(\"Unknown pointer size\");\n        }\n        BUFFER_PAD = BUFFER_PADDING_BYTES / scale;\n        // Including the buffer pad in the array base offset\n        REF_ARRAY_BASE = UNSAFE.arrayBaseOffset(Object[].class) + BUFFER_PADDING_BYTES;\n    }\n\n    private final long indexMask;\n    private final Object[] entries;\n    protected final int bufferSize;\n    protected final Sequencer sequencer;\n\n    RingBufferFieldsUnsafe(\n            final EventFactory<E> eventFactory,\n            final Sequencer sequencer)\n    {\n        this.sequencer = sequencer;\n        this.bufferSize = sequencer.getBufferSize();\n\n        if (bufferSize < 1)\n        {\n            throw new IllegalArgumentException(\"bufferSize must not be less than 1\");\n        }\n        if (Integer.bitCount(bufferSize) != 1)\n        {\n            throw new IllegalArgumentException(\"bufferSize must be a power of 2\");\n        }\n\n        this.indexMask = bufferSize - 1;\n        this.entries = new Object[sequencer.getBufferSize() + 2 * BUFFER_PAD];\n        fill(eventFactory);\n    }\n\n    private void fill(final EventFactory<E> eventFactory)\n    {\n        for (int i = 0; i < bufferSize; i++)\n        {\n            entries[BUFFER_PAD + i] = eventFactory.newInstance();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    protected final E elementAt(final long sequence)\n    {\n        return (E) UNSAFE.getObject(entries, REF_ARRAY_BASE + ((sequence & indexMask) << REF_ELEMENT_SHIFT));\n    }\n}\n\n/**\n * Ring based store of reusable entries containing the data representing\n * an event being exchanged between event producer and {@link EventProcessor}s.\n *\n * @param <E> implementation storing the data for sharing during exchange or parallel coordination of an event.\n */\npublic final class RingBufferUnsafe<E> extends RingBufferFieldsUnsafe<E> implements Cursored, EventSequencer<E>, EventSink<E>\n{\n    public static final long INITIAL_CURSOR_VALUE = SequenceUnsafe.INITIAL_VALUE;\n    protected byte\n            p10, p11, p12, p13, p14, p15, p16, p17,\n            p20, p21, p22, p23, p24, p25, p26, p27,\n            p30, p31, p32, p33, p34, p35, p36, p37,\n            p40, p41, p42, p43, p44, p45, p46, p47,\n            p50, p51, p52, p53, p54, p55, p56, p57,\n            p60, p61, p62, p63, p64, p65, p66, p67,\n            p70, p71, p72, p73, p74, p75, p76, p77;\n\n    /**\n     * Construct a RingBuffer with the full option set.\n     *\n     * @param eventFactory to newInstance entries for filling the RingBuffer\n     * @param sequencer    sequencer to handle the ordering of events moving through the RingBuffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     */\n    public RingBufferUnsafe(\n            final EventFactory<E> eventFactory,\n            final Sequencer sequencer)\n    {\n        super(eventFactory, sequencer);\n    }\n\n    /**\n     * Create a new multiple producer RingBuffer with the specified wait strategy.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory      used to create the events within the ring buffer.\n     * @param bufferSize   number of elements to create within the ring buffer.\n     * @param waitStrategy used to determine how to wait for new elements to become available.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     * @see MultiProducerSequencer\n     */\n    public static <E> RingBufferUnsafe<E> createMultiProducer(\n            final EventFactory<E> factory,\n            final int bufferSize,\n            final WaitStrategy waitStrategy)\n    {\n        MultiProducerSequencer sequencer = new MultiProducerSequencer(bufferSize, waitStrategy);\n\n        return new RingBufferUnsafe<>(factory, sequencer);\n    }\n\n    /**\n     * Create a new multiple producer RingBuffer using the default wait strategy  {@link BlockingWaitStrategy}.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory    used to create the events within the ring buffer.\n     * @param bufferSize number of elements to create within the ring buffer.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if <code>bufferSize</code> is less than 1 or not a power of 2\n     * @see MultiProducerSequencer\n     */\n    public static <E> RingBufferUnsafe<E> createMultiProducer(final EventFactory<E> factory, final int bufferSize)\n    {\n        return createMultiProducer(factory, bufferSize, new BlockingWaitStrategy());\n    }\n\n    /**\n     * Create a new single producer RingBuffer with the specified wait strategy.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory      used to create the events within the ring buffer.\n     * @param bufferSize   number of elements to create within the ring buffer.\n     * @param waitStrategy used to determine how to wait for new elements to become available.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     * @see SingleProducerSequencer\n     */\n    public static <E> RingBufferUnsafe<E> createSingleProducer(\n            final EventFactory<E> factory,\n            final int bufferSize,\n            final WaitStrategy waitStrategy)\n    {\n        SingleProducerSequencer sequencer = new SingleProducerSequencer(bufferSize, waitStrategy);\n\n        return new RingBufferUnsafe<>(factory, sequencer);\n    }\n\n    /**\n     * Create a new single producer RingBuffer using the default wait strategy  {@link BlockingWaitStrategy}.\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param factory    used to create the events within the ring buffer.\n     * @param bufferSize number of elements to create within the ring buffer.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if <code>bufferSize</code> is less than 1 or not a power of 2\n     * @see MultiProducerSequencer\n     */\n    public static <E> RingBufferUnsafe<E> createSingleProducer(final EventFactory<E> factory, final int bufferSize)\n    {\n        return createSingleProducer(factory, bufferSize, new BlockingWaitStrategy());\n    }\n\n    /**\n     * Create a new Ring Buffer with the specified producer type (SINGLE or MULTI)\n     *\n     * @param <E> Class of the event stored in the ring buffer.\n     * @param producerType producer type to use {@link ProducerType}.\n     * @param factory      used to create events within the ring buffer.\n     * @param bufferSize   number of elements to create within the ring buffer.\n     * @param waitStrategy used to determine how to wait for new elements to become available.\n     * @return a constructed ring buffer.\n     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2\n     */\n    public static <E> RingBufferUnsafe<E> create(\n            final ProducerType producerType,\n            final EventFactory<E> factory,\n            final int bufferSize,\n            final WaitStrategy waitStrategy)\n    {\n        switch (producerType)\n        {\n            case SINGLE:\n                return createSingleProducer(factory, bufferSize, waitStrategy);\n            case MULTI:\n                return createMultiProducer(factory, bufferSize, waitStrategy);\n            default:\n                throw new IllegalStateException(producerType.toString());\n        }\n    }\n\n    /**\n     * <p>Get the event for a given sequence in the RingBuffer.</p>\n     *\n     * <p>This call has 2 uses.  Firstly use this call when publishing to a ring buffer.\n     * After calling {@link com.lmax.disruptor.RingBuffer#next()} use this call to get hold of the\n     * preallocated event to fill with data before calling {@link com.lmax.disruptor.RingBuffer#publish(long)}.</p>\n     *\n     * <p>Secondly use this call when consuming data from the ring buffer.  After calling\n     * {@link SequenceBarrier#waitFor(long)} call this method with any value greater than\n     * that your current consumer sequence and less than or equal to the value returned from\n     * the {@link SequenceBarrier#waitFor(long)} method.</p>\n     *\n     * @param sequence for the event\n     * @return the event for the given sequence\n     */\n    @Override\n    public E get(final long sequence)\n    {\n        return elementAt(sequence);\n    }\n\n    /**\n     * Increment and return the next sequence for the ring buffer.  Calls of this\n     * method should ensure that they always publish the sequence afterward.  E.g.\n     * <pre>\n     * long sequence = ringBuffer.next();\n     * try {\n     *     Event e = ringBuffer.get(sequence);\n     *     // Do some work with the event.\n     * } finally {\n     *     ringBuffer.publish(sequence);\n     * }\n     * </pre>\n     *\n     * @return The next sequence to publish to.\n     * @see com.lmax.disruptor.RingBuffer#publish(long)\n     * @see com.lmax.disruptor.RingBuffer#get(long)\n     */\n    @Override\n    public long next()\n    {\n        return sequencer.next();\n    }\n\n    /**\n     * The same functionality as {@link com.lmax.disruptor.RingBuffer#next()}, but allows the caller to claim\n     * the next n sequences.\n     *\n     * @param n number of slots to claim\n     * @return sequence number of the highest slot claimed\n     * @see Sequencer#next(int)\n     */\n    @Override\n    public long next(final int n)\n    {\n        return sequencer.next(n);\n    }\n\n    /**\n     * <p>Increment and return the next sequence for the ring buffer.  Calls of this\n     * method should ensure that they always publish the sequence afterward.  E.g.</p>\n     * <pre>\n     * long sequence = ringBuffer.next();\n     * try {\n     *     Event e = ringBuffer.get(sequence);\n     *     // Do some work with the event.\n     * } finally {\n     *     ringBuffer.publish(sequence);\n     * }\n     * </pre>\n     * <p>This method will not block if there is not space available in the ring\n     * buffer, instead it will throw an {@link InsufficientCapacityException}.</p>\n     *\n     * @return The next sequence to publish to.\n     * @throws InsufficientCapacityException if the necessary space in the ring buffer is not available\n     * @see com.lmax.disruptor.RingBuffer#publish(long)\n     * @see com.lmax.disruptor.RingBuffer#get(long)\n     */\n    @Override\n    public long tryNext() throws InsufficientCapacityException\n    {\n        return sequencer.tryNext();\n    }\n\n    /**\n     * The same functionality as {@link com.lmax.disruptor.RingBuffer#tryNext()}, but allows the caller to attempt\n     * to claim the next n sequences.\n     *\n     * @param n number of slots to claim\n     * @return sequence number of the highest slot claimed\n     * @throws InsufficientCapacityException if the necessary space in the ring buffer is not available\n     */\n    @Override\n    public long tryNext(final int n) throws InsufficientCapacityException\n    {\n        return sequencer.tryNext(n);\n    }\n\n    /**\n     * Resets the cursor to a specific value.  This can be applied at any time, but it is worth noting\n     * that it can cause a data race and should only be used in controlled circumstances.  E.g. during\n     * initialisation.\n     *\n     * @param sequence The sequence to reset too.\n     * @throws IllegalStateException If any gating sequences have already been specified.\n     */\n    @Deprecated\n    public void resetTo(final long sequence)\n    {\n        sequencer.claim(sequence);\n        sequencer.publish(sequence);\n    }\n\n    /**\n     * Sets the cursor to a specific sequence and returns the preallocated entry that is stored there.  This\n     * can cause a data race and should only be done in controlled circumstances, e.g. during initialisation.\n     *\n     * @param sequence The sequence to claim.\n     * @return The preallocated event.\n     */\n    public E claimAndGetPreallocated(final long sequence)\n    {\n        sequencer.claim(sequence);\n        return get(sequence);\n    }\n\n    /**\n     * Determines if the event for a given sequence is currently available.\n     *\n     * <p>Note that this does not guarantee that event will still be available\n     * on the next interaction with the RingBuffer. For example, it is not\n     * necessarily safe to write code like this:\n     *\n     * <pre>{@code\n     * if (ringBuffer.isAvailable(sequence))\n     * {\n     *     final E e = ringBuffer.get(sequence);\n     *     // ...do something with e\n     * }\n     * }</pre>\n     *\n     * <p>because there is a race between the reading thread and the writing thread.\n     *\n     * <p>This method will also return false when querying for sequences that are\n     * behind the ring buffer's wrap point.\n     *\n     * @param sequence The sequence to identify the entry.\n     * @return If the event published with the given sequence number is currently available.\n     */\n    public boolean isAvailable(final long sequence)\n    {\n        return sequencer.isAvailable(sequence);\n    }\n\n    /**\n     * Add the specified gating sequences to this instance of the Disruptor.  They will\n     * safely and atomically added to the list of gating sequences.\n     *\n     * @param gatingSequences The sequences to add.\n     */\n    public void addGatingSequences(final Sequence... gatingSequences)\n    {\n        sequencer.addGatingSequences(gatingSequences);\n    }\n\n    /**\n     * Get the minimum sequence value from all of the gating sequences\n     * added to this ringBuffer.\n     *\n     * @return The minimum gating sequence or the cursor sequence if\n     * no sequences have been added.\n     */\n    public long getMinimumGatingSequence()\n    {\n        return sequencer.getMinimumSequence();\n    }\n\n    /**\n     * Remove the specified sequence from this ringBuffer.\n     *\n     * @param sequence to be removed.\n     * @return <code>true</code> if this sequence was found, <code>false</code> otherwise.\n     */\n    public boolean removeGatingSequence(final Sequence sequence)\n    {\n        return sequencer.removeGatingSequence(sequence);\n    }\n\n    /**\n     * Create a new SequenceBarrier to be used by an EventProcessor to track which messages\n     * are available to be read from the ring buffer given a list of sequences to track.\n     *\n     * @param sequencesToTrack the additional sequences to track\n     * @return A sequence barrier that will track the specified sequences.\n     * @see SequenceBarrier\n     */\n    public SequenceBarrier newBarrier(final Sequence... sequencesToTrack)\n    {\n        return sequencer.newBarrier(sequencesToTrack);\n    }\n\n    /**\n     * Creates an event poller for this ring buffer gated on the supplied sequences.\n     *\n     * @param gatingSequences to be gated on.\n     * @return A poller that will gate on this ring buffer and the supplied sequences.\n     */\n    public EventPoller<E> newPoller(final Sequence... gatingSequences)\n    {\n        return sequencer.newPoller(this, gatingSequences);\n    }\n\n    /**\n     * Get the current cursor value for the ring buffer.  The actual value received\n     * will depend on the type of {@link Sequencer} that is being used.\n     *\n     * @see MultiProducerSequencer\n     * @see SingleProducerSequencer\n     */\n    @Override\n    public long getCursor()\n    {\n        return sequencer.getCursor();\n    }\n\n    /**\n     * The size of the buffer.\n     *\n     * @return size of buffer\n     */\n    @Override\n    public int getBufferSize()\n    {\n        return bufferSize;\n    }\n\n    /**\n     * Given specified <code>requiredCapacity</code> determines if that amount of space\n     * is available.  Note, you can not assume that if this method returns <code>true</code>\n     * that a call to {@link com.lmax.disruptor.RingBuffer#next()} will not block.  Especially true if this\n     * ring buffer is set up to handle multiple producers.\n     *\n     * @param requiredCapacity The capacity to check for.\n     * @return <code>true</code> If the specified <code>requiredCapacity</code> is available\n     * <code>false</code> if not.\n     */\n    @Override\n    public boolean hasAvailableCapacity(final int requiredCapacity)\n    {\n        return sequencer.hasAvailableCapacity(requiredCapacity);\n    }\n\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslator)\n     */\n    @Override\n    public void publishEvent(final EventTranslator<E> translator)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslator)\n     */\n    @Override\n    public boolean tryPublishEvent(final EventTranslator<E> translator)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorOneArg, Object)\n     * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorOneArg, A)\n     */\n    @Override\n    public <A> void publishEvent(final EventTranslatorOneArg<E, A> translator, final A arg0)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, arg0);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorOneArg, Object)\n     * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorOneArg, A)\n     */\n    @Override\n    public <A> boolean tryPublishEvent(final EventTranslatorOneArg<E, A> translator, final A arg0)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, arg0);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorTwoArg, Object, Object)\n     * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorTwoArg, A, B)\n     */\n    @Override\n    public <A, B> void publishEvent(final EventTranslatorTwoArg<E, A, B> translator, final A arg0, final B arg1)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, arg0, arg1);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorTwoArg, Object, Object)\n     * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorTwoArg, A, B)\n     */\n    @Override\n    public <A, B> boolean tryPublishEvent(final EventTranslatorTwoArg<E, A, B> translator, final A arg0, final B arg1)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, arg0, arg1);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorThreeArg, Object, Object, Object)\n     * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorThreeArg, A, B, C)\n     */\n    @Override\n    public <A, B, C> void publishEvent(final EventTranslatorThreeArg<E, A, B, C> translator, final A arg0, final B arg1, final C arg2)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, arg0, arg1, arg2);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorThreeArg, Object, Object, Object)\n     * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorThreeArg, A, B, C)\n     */\n    @Override\n    public <A, B, C> boolean tryPublishEvent(final EventTranslatorThreeArg<E, A, B, C> translator, final A arg0, final B arg1, final C arg2)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, arg0, arg1, arg2);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object...)\n     */\n    @Override\n    public void publishEvent(final EventTranslatorVararg<E> translator, final Object... args)\n    {\n        final long sequence = sequencer.next();\n        translateAndPublish(translator, sequence, args);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object...)\n     */\n    @Override\n    public boolean tryPublishEvent(final EventTranslatorVararg<E> translator, final Object... args)\n    {\n        try\n        {\n            final long sequence = sequencer.tryNext();\n            translateAndPublish(translator, sequence, args);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    @Override\n    public void publishEvents(final EventTranslator<E>[] translators)\n    {\n        publishEvents(translators, 0, translators.length);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslator[], int, int)\n     */\n    @Override\n    public void publishEvents(final EventTranslator<E>[] translators, final int batchStartsAt, final int batchSize)\n    {\n        checkBounds(translators, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translators, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslator[])\n     */\n    @Override\n    public boolean tryPublishEvents(final EventTranslator<E>[] translators)\n    {\n        return tryPublishEvents(translators, 0, translators.length);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslator[], int, int)\n     */\n    @Override\n    public boolean tryPublishEvents(final EventTranslator<E>[] translators, final int batchStartsAt, final int batchSize)\n    {\n        checkBounds(translators, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translators, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, A[])\n     */\n    @Override\n    public <A> void publishEvents(final EventTranslatorOneArg<E, A> translator, final A[] arg0)\n    {\n        publishEvents(translator, 0, arg0.length, arg0);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, A[])\n     */\n    @Override\n    public <A> void publishEvents(final EventTranslatorOneArg<E, A> translator, final int batchStartsAt, final int batchSize, final A[] arg0)\n    {\n        checkBounds(arg0, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, arg0, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, A[])\n     */\n    @Override\n    public <A> boolean tryPublishEvents(final EventTranslatorOneArg<E, A> translator, final A[] arg0)\n    {\n        return tryPublishEvents(translator, 0, arg0.length, arg0);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, A[])\n     */\n    @Override\n    public <A> boolean tryPublishEvents(\n            final EventTranslatorOneArg<E, A> translator, final int batchStartsAt, final int batchSize, final A[] arg0)\n    {\n        checkBounds(arg0, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, arg0, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, A[], B[])\n     */\n    @Override\n    public <A, B> void publishEvents(final EventTranslatorTwoArg<E, A, B> translator, final A[] arg0, final B[] arg1)\n    {\n        publishEvents(translator, 0, arg0.length, arg0, arg1);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, A[], B[])\n     */\n    @Override\n    public <A, B> void publishEvents(\n            final EventTranslatorTwoArg<E, A, B> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1)\n    {\n        checkBounds(arg0, arg1, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, arg0, arg1, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, A[], B[])\n     */\n    @Override\n    public <A, B> boolean tryPublishEvents(final EventTranslatorTwoArg<E, A, B> translator, final A[] arg0, final B[] arg1)\n    {\n        return tryPublishEvents(translator, 0, arg0.length, arg0, arg1);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, A[], B[])\n     */\n    @Override\n    public <A, B> boolean tryPublishEvents(\n            final EventTranslatorTwoArg<E, A, B> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1)\n    {\n        checkBounds(arg0, arg1, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, arg0, arg1, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> void publishEvents(final EventTranslatorThreeArg<E, A, B, C> translator, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        publishEvents(translator, 0, arg0.length, arg0, arg1, arg2);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> void publishEvents(\n            final EventTranslatorThreeArg<E, A, B, C> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        checkBounds(arg0, arg1, arg2, batchStartsAt, batchSize);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, arg0, arg1, arg2, batchStartsAt, batchSize, finalSequence);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> boolean tryPublishEvents(\n            final EventTranslatorThreeArg<E, A, B, C> translator, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        return tryPublishEvents(translator, 0, arg0.length, arg0, arg1, arg2);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, Object[], Object[], Object[])\n     * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, A[], B[], C[])\n     */\n    @Override\n    public <A, B, C> boolean tryPublishEvents(\n            final EventTranslatorThreeArg<E, A, B, C> translator, final int batchStartsAt, final int batchSize, final A[] arg0, final B[] arg1, final C[] arg2)\n    {\n        checkBounds(arg0, arg1, arg2, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, arg0, arg1, arg2, batchStartsAt, batchSize, finalSequence);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object[][])\n     */\n    @Override\n    public void publishEvents(final EventTranslatorVararg<E> translator, final Object[]... args)\n    {\n        publishEvents(translator, 0, args.length, args);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorVararg, int, int, java.lang.Object[][])\n     */\n    @Override\n    public void publishEvents(final EventTranslatorVararg<E> translator, final int batchStartsAt, final int batchSize, final Object[]... args)\n    {\n        checkBounds(batchStartsAt, batchSize, args);\n        final long finalSequence = sequencer.next(batchSize);\n        translateAndPublishBatch(translator, batchStartsAt, batchSize, finalSequence, args);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object[][])\n     */\n    @Override\n    public boolean tryPublishEvents(final EventTranslatorVararg<E> translator, final Object[]... args)\n    {\n        return tryPublishEvents(translator, 0, args.length, args);\n    }\n\n    /**\n     * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorVararg, int, int, java.lang.Object[][])\n     */\n    @Override\n    public boolean tryPublishEvents(\n            final EventTranslatorVararg<E> translator, final int batchStartsAt, final int batchSize, final Object[]... args)\n    {\n        checkBounds(args, batchStartsAt, batchSize);\n        try\n        {\n            final long finalSequence = sequencer.tryNext(batchSize);\n            translateAndPublishBatch(translator, batchStartsAt, batchSize, finalSequence, args);\n            return true;\n        }\n        catch (InsufficientCapacityException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * Publish the specified sequence.  This action marks this particular\n     * message as being available to be read.\n     *\n     * @param sequence the sequence to publish.\n     */\n    @Override\n    public void publish(final long sequence)\n    {\n        sequencer.publish(sequence);\n    }\n\n    /**\n     * Publish the specified sequences.  This action marks these particular\n     * messages as being available to be read.\n     *\n     * @param lo the lowest sequence number to be published\n     * @param hi the highest sequence number to be published\n     * @see Sequencer#next(int)\n     */\n    @Override\n    public void publish(final long lo, final long hi)\n    {\n        sequencer.publish(lo, hi);\n    }\n\n    /**\n     * Get the remaining capacity for this ringBuffer.\n     *\n     * @return The number of slots remaining.\n     */\n    @Override\n    public long remainingCapacity()\n    {\n        return sequencer.remainingCapacity();\n    }\n\n    private void checkBounds(final EventTranslator<E>[] translators, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(translators, batchStartsAt, batchSize);\n    }\n\n    private void checkBatchSizing(final int batchStartsAt, final int batchSize)\n    {\n        if (batchStartsAt < 0 || batchSize < 0)\n        {\n            throw new IllegalArgumentException(\"Both batchStartsAt and batchSize must be positive but got: batchStartsAt \" + batchStartsAt + \" and batchSize \" + batchSize);\n        }\n        else if (batchSize > bufferSize)\n        {\n            throw new IllegalArgumentException(\"The ring buffer cannot accommodate \" + batchSize + \" it only has space for \" + bufferSize + \" entities.\");\n        }\n    }\n\n    private <A> void checkBounds(final A[] arg0, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(arg0, batchStartsAt, batchSize);\n    }\n\n    private <A, B> void checkBounds(final A[] arg0, final B[] arg1, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(arg0, batchStartsAt, batchSize);\n        batchOverRuns(arg1, batchStartsAt, batchSize);\n    }\n\n    private <A, B, C> void checkBounds(\n            final A[] arg0, final B[] arg1, final C[] arg2, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(arg0, batchStartsAt, batchSize);\n        batchOverRuns(arg1, batchStartsAt, batchSize);\n        batchOverRuns(arg2, batchStartsAt, batchSize);\n    }\n\n    private void checkBounds(final int batchStartsAt, final int batchSize, final Object[][] args)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(args, batchStartsAt, batchSize);\n    }\n\n    private <A> void batchOverRuns(final A[] arg0, final int batchStartsAt, final int batchSize)\n    {\n        if (batchStartsAt + batchSize > arg0.length)\n        {\n            throw new IllegalArgumentException(\n                    \"A batchSize of: \" + batchSize +\n                            \" with batchStatsAt of: \" + batchStartsAt +\n                            \" will overrun the available number of arguments: \" + (arg0.length - batchStartsAt));\n        }\n    }\n\n    private void translateAndPublish(final EventTranslator<E> translator, final long sequence)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private <A> void translateAndPublish(final EventTranslatorOneArg<E, A> translator, final long sequence, final A arg0)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, arg0);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private <A, B> void translateAndPublish(final EventTranslatorTwoArg<E, A, B> translator, final long sequence, final A arg0, final B arg1)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, arg0, arg1);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private <A, B, C> void translateAndPublish(\n            final EventTranslatorThreeArg<E, A, B, C> translator, final long sequence,\n            final A arg0, final B arg1, final C arg2)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, arg0, arg1, arg2);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private void translateAndPublish(final EventTranslatorVararg<E> translator, final long sequence, final Object... args)\n    {\n        try\n        {\n            translator.translateTo(get(sequence), sequence, args);\n        }\n        finally\n        {\n            sequencer.publish(sequence);\n        }\n    }\n\n    private void translateAndPublishBatch(\n            final EventTranslator<E>[] translators, final int batchStartsAt,\n            final int batchSize, final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                final EventTranslator<E> translator = translators[i];\n                translator.translateTo(get(sequence), sequence++);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private <A> void translateAndPublishBatch(\n            final EventTranslatorOneArg<E, A> translator, final A[] arg0,\n            final int batchStartsAt, final int batchSize, final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, arg0[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private <A, B> void translateAndPublishBatch(\n            final EventTranslatorTwoArg<E, A, B> translator, final A[] arg0,\n            final B[] arg1, final int batchStartsAt, final int batchSize,\n            final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, arg0[i], arg1[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private <A, B, C> void translateAndPublishBatch(\n            final EventTranslatorThreeArg<E, A, B, C> translator,\n            final A[] arg0, final B[] arg1, final C[] arg2, final int batchStartsAt,\n            final int batchSize, final long finalSequence)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, arg0[i], arg1[i], arg2[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    private void translateAndPublishBatch(\n            final EventTranslatorVararg<E> translator, final int batchStartsAt,\n            final int batchSize, final long finalSequence, final Object[][] args)\n    {\n        final long initialSequence = finalSequence - (batchSize - 1);\n        try\n        {\n            long sequence = initialSequence;\n            final int batchEndsAt = batchStartsAt + batchSize;\n            for (int i = batchStartsAt; i < batchEndsAt; i++)\n            {\n                translator.translateTo(get(sequence), sequence++, args[i]);\n            }\n        }\n        finally\n        {\n            sequencer.publish(initialSequence, finalSequence);\n        }\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"RingBuffer{\" +\n                \"bufferSize=\" + bufferSize +\n                \", sequencer=\" + sequencer +\n                \"}\";\n    }\n}\n\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/alternatives/SequenceDoublePadded.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.alternatives;\n\nimport com.lmax.disruptor.util.UnsafeAccess;\nimport sun.misc.Unsafe;\n\n// https://github.com/LMAX-Exchange/disruptor/issues/231\n\nclass LhsPaddingDouble\n{\n    protected long\n            p1, p2, p3, p4, p5, p6, p7, p8,\n            p9, p10, p11, p12, p13, p14, p15;\n}\n\nclass ValueDoublePadded extends LhsPaddingDouble\n{\n    protected volatile long value;\n}\n\nclass RhsPaddingDouble extends ValueDoublePadded\n{\n    protected long\n            p1, p2, p3, p4, p5, p6, p7, p8,\n            p9, p10, p11, p12, p13, p14, p15;\n}\n\n/**\n * Concurrent sequence class used for tracking the progress of\n * the ring buffer and event processors.  Support a number\n * of concurrent operations including CAS and order writes.\n *\n * <p>Also attempts to be more efficient with regards to false\n * sharing by adding padding around the volatile field.\n */\npublic class SequenceDoublePadded extends RhsPaddingDouble\n{\n    static final long INITIAL_VALUE = -1L;\n    private static final Unsafe UNSAFE;\n    private static final long VALUE_OFFSET;\n\n    static\n    {\n        UNSAFE = UnsafeAccess.getUnsafe();\n        try\n        {\n            VALUE_OFFSET = UNSAFE.objectFieldOffset(ValueDoublePadded.class.getDeclaredField(\"value\"));\n        }\n        catch (final Exception e)\n        {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Create a sequence initialised to -1.\n     */\n    public SequenceDoublePadded()\n    {\n        this(INITIAL_VALUE);\n    }\n\n    /**\n     * Create a sequence with a specified initial value.\n     *\n     * @param initialValue The initial value for this sequence.\n     */\n    public SequenceDoublePadded(final long initialValue)\n    {\n        UNSAFE.putOrderedLong(this, VALUE_OFFSET, initialValue);\n    }\n\n    /**\n     * Perform a volatile read of this sequence's value.\n     *\n     * @return The current value of the sequence.\n     */\n    public long get()\n    {\n        return value;\n    }\n\n    /**\n     * Perform an ordered write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * store.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void set(final long value)\n    {\n        UNSAFE.putOrderedLong(this, VALUE_OFFSET, value);\n    }\n\n    /**\n     * Performs a volatile write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * write and a Store/Load barrier between this write and any\n     * subsequent volatile read.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void setVolatile(final long value)\n    {\n        UNSAFE.putLongVolatile(this, VALUE_OFFSET, value);\n    }\n\n    /**\n     * Perform a compare and set operation on the sequence.\n     *\n     * @param expectedValue The expected current value.\n     * @param newValue The value to update to.\n     * @return true if the operation succeeds, false otherwise.\n     */\n    public boolean compareAndSet(final long expectedValue, final long newValue)\n    {\n        return UNSAFE.compareAndSwapLong(this, VALUE_OFFSET, expectedValue, newValue);\n    }\n\n    /**\n     * Atomically increment the sequence by one.\n     *\n     * @return The value after the increment\n     */\n    public long incrementAndGet()\n    {\n        return addAndGet(1L);\n    }\n\n    /**\n     * Atomically add the supplied value.\n     *\n     * @param increment The value to add to the sequence.\n     * @return The value after the increment.\n     */\n    public long addAndGet(final long increment)\n    {\n        long currentValue;\n        long newValue;\n\n        do\n        {\n            currentValue = get();\n            newValue = currentValue + increment;\n        }\n        while (!compareAndSet(currentValue, newValue));\n\n        return newValue;\n    }\n\n    @Override\n    public String toString()\n    {\n        return Long.toString(get());\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/alternatives/SequenceUnsafe.java",
    "content": "package com.lmax.disruptor.alternatives;\n\nimport com.lmax.disruptor.util.UnsafeAccess;\nimport sun.misc.Unsafe;\n\nclass LhsPaddingUnsafe\n{\n    protected byte\n        p10, p11, p12, p13, p14, p15, p16, p17,\n        p20, p21, p22, p23, p24, p25, p26, p27,\n        p30, p31, p32, p33, p34, p35, p36, p37,\n        p40, p41, p42, p43, p44, p45, p46, p47,\n        p50, p51, p52, p53, p54, p55, p56, p57,\n        p60, p61, p62, p63, p64, p65, p66, p67,\n        p70, p71, p72, p73, p74, p75, p76, p77;\n}\n\nclass ValueUnsafe extends LhsPaddingUnsafe\n{\n    protected volatile long value;\n}\n\nclass RhsPaddingUnsafe extends ValueUnsafe\n{\n    protected byte\n        p90, p91, p92, p93, p94, p95, p96, p97,\n        p100, p101, p102, p103, p104, p105, p106, p107,\n        p110, p111, p112, p113, p114, p115, p116, p117,\n        p120, p121, p122, p123, p124, p125, p126, p127,\n        p130, p131, p132, p133, p134, p135, p136, p137,\n        p140, p141, p142, p143, p144, p145, p146, p147,\n        p150, p151, p152, p153, p154, p155, p156, p157;\n}\n\n/**\n * Concurrent sequence class used for tracking the progress of\n * the ring buffer and event processors.  Support a number\n * of concurrent operations including CAS and order writes.\n *\n * <p>Also attempts to be more efficient with regards to false\n * sharing by adding padding around the volatile field.\n */\npublic class SequenceUnsafe extends RhsPaddingUnsafe\n{\n    static final long INITIAL_VALUE = -1L;\n    private static final Unsafe UNSAFE;\n    private static final long VALUE_OFFSET;\n\n    static\n    {\n        UNSAFE = UnsafeAccess.getUnsafe();\n        try\n        {\n            VALUE_OFFSET = UNSAFE.objectFieldOffset(ValueUnsafe.class.getDeclaredField(\"value\"));\n        }\n        catch (final Exception e)\n        {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Create a sequence initialised to -1.\n     */\n    public SequenceUnsafe()\n    {\n        this(INITIAL_VALUE);\n    }\n\n    /**\n     * Create a sequence with a specified initial value.\n     *\n     * @param initialValue The initial value for this sequence.\n     */\n    public SequenceUnsafe(final long initialValue)\n    {\n        UNSAFE.putOrderedLong(this, VALUE_OFFSET, initialValue);\n    }\n\n    /**\n     * Perform a volatile read of this sequence's value.\n     *\n     * @return The current value of the sequence.\n     */\n    public long get()\n    {\n        return value;\n    }\n\n    /**\n     * Perform an ordered write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * store.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void set(final long value)\n    {\n        UNSAFE.putOrderedLong(this, VALUE_OFFSET, value);\n    }\n\n    /**\n     * Performs a volatile write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * write and a Store/Load barrier between this write and any\n     * subsequent volatile read.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void setVolatile(final long value)\n    {\n        UNSAFE.putLongVolatile(this, VALUE_OFFSET, value);\n    }\n\n    /**\n     * Perform a compare and set operation on the sequence.\n     *\n     * @param expectedValue The expected current value.\n     * @param newValue      The value to update to.\n     * @return true if the operation succeeds, false otherwise.\n     */\n    public boolean compareAndSet(final long expectedValue, final long newValue)\n    {\n        return UNSAFE.compareAndSwapLong(this, VALUE_OFFSET, expectedValue, newValue);\n    }\n\n    /**\n     * Atomically increment the sequence by one.\n     *\n     * @return The value after the increment\n     */\n    public long incrementAndGet()\n    {\n        return addAndGet(1L);\n    }\n\n    /**\n     * Atomically add the supplied value.\n     *\n     * @param increment The value to add to the sequence.\n     * @return The value after the increment.\n     */\n    public long addAndGet(final long increment)\n    {\n        long currentValue;\n        long newValue;\n\n        do\n        {\n            currentValue = get();\n            newValue = currentValue + increment;\n        }\n        while (!compareAndSet(currentValue, newValue));\n\n        return newValue;\n    }\n\n    @Override\n    public String toString()\n    {\n        return Long.toString(get());\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/alternatives/SequenceVarHandle.java",
    "content": "package com.lmax.disruptor.alternatives;\n\n\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.VarHandle;\n\nclass LhsPaddingVarHandle\n{\n    protected byte\n        p10, p11, p12, p13, p14, p15, p16, p17,\n        p20, p21, p22, p23, p24, p25, p26, p27,\n        p30, p31, p32, p33, p34, p35, p36, p37,\n        p40, p41, p42, p43, p44, p45, p46, p47,\n        p50, p51, p52, p53, p54, p55, p56, p57,\n        p60, p61, p62, p63, p64, p65, p66, p67,\n        p70, p71, p72, p73, p74, p75, p76, p77;\n}\n\nclass ValueVarHandle extends LhsPaddingVarHandle\n{\n    protected volatile long value;\n}\n\nclass RhsPaddingVarHandle extends ValueVarHandle\n{\n    protected byte\n        p90, p91, p92, p93, p94, p95, p96, p97,\n        p100, p101, p102, p103, p104, p105, p106, p107,\n        p110, p111, p112, p113, p114, p115, p116, p117,\n        p120, p121, p122, p123, p124, p125, p126, p127,\n        p130, p131, p132, p133, p134, p135, p136, p137,\n        p140, p141, p142, p143, p144, p145, p146, p147,\n        p150, p151, p152, p153, p154, p155, p156, p157;\n}\n\n/**\n * Concurrent sequence class used for tracking the progress of\n * the ring buffer and event processors.  Support a number\n * of concurrent operations including CAS and order writes.\n *\n * <p>Also attempts to be more efficient with regards to false\n * sharing by adding padding around the volatile field.\n */\npublic class SequenceVarHandle extends RhsPaddingVarHandle\n{\n    static final long INITIAL_VALUE = -1L;\n    private static final VarHandle VALUE_FIELD;\n\n    static\n    {\n        try\n        {\n            VALUE_FIELD = MethodHandles.lookup().in(SequenceVarHandle.class)\n                    .findVarHandle(SequenceVarHandle.class, \"value\", long.class);\n        }\n        catch (final Exception e)\n        {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Create a sequence initialised to -1.\n     */\n    public SequenceVarHandle()\n    {\n        this(INITIAL_VALUE);\n    }\n\n    /**\n     * Create a sequence with a specified initial value.\n     *\n     * @param initialValue The initial value for this sequence.\n     */\n    public SequenceVarHandle(final long initialValue)\n    {\n        VALUE_FIELD.setRelease(this, initialValue);\n    }\n\n    /**\n     * Perform a volatile read of this sequence's value.\n     *\n     * @return The current value of the sequence.\n     */\n    public long get()\n    {\n        return (long) VALUE_FIELD.getAcquire(this);\n    }\n\n    /**\n     * Perform an ordered write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * store.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void set(final long value)\n    {\n        VALUE_FIELD.setRelease(this, value);\n    }\n\n    /**\n     * Performs a volatile write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * write and a Store/Load barrier between this write and any\n     * subsequent volatile read.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void setVolatile(final long value)\n    {\n        VALUE_FIELD.setVolatile(this, value);\n    }\n\n    /**\n     * Perform a compare and set operation on the sequence.\n     *\n     * @param expectedValue The expected current value.\n     * @param newValue      The value to update to.\n     * @return true if the operation succeeds, false otherwise.\n     */\n    public boolean compareAndSet(final long expectedValue, final long newValue)\n    {\n        return VALUE_FIELD.compareAndSet(this, expectedValue, newValue);\n    }\n\n    /**\n     * Atomically increment the sequence by one.\n     *\n     * @return The value after the increment\n     */\n    public long incrementAndGet()\n    {\n        return addAndGet(1L);\n    }\n\n    /**\n     * Atomically add the supplied value.\n     *\n     * @param increment The value to add to the sequence.\n     * @return The value after the increment.\n     */\n    public long addAndGet(final long increment)\n    {\n        return (long) VALUE_FIELD.getAndAdd(this, increment) + increment;\n    }\n\n    @Override\n    public String toString()\n    {\n        return Long.toString(get());\n    }\n}"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/alternatives/SequenceVarHandleArray.java",
    "content": "package com.lmax.disruptor.alternatives;\n\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.VarHandle;\n\n\n/**\n * Concurrent sequence class used for tracking the progress of\n * the ring buffer and event processors.  Support a number\n * of concurrent operations including CAS and order writes.\n *\n * <p>Also attempts to be more efficient with regards to false\n * sharing by adding padding around the volatile field.\n */\npublic class SequenceVarHandleArray\n{\n    private static final int VALUE_INDEX = 8;\n    private static final VarHandle VALUE_FIELD = MethodHandles.arrayElementVarHandle(long[].class);\n\n    private final long[] paddedValue = new long[16];\n\n    static final long INITIAL_VALUE = -1L;\n\n    /**\n     * Create a sequence initialised to -1.\n     */\n    public SequenceVarHandleArray()\n    {\n        this(INITIAL_VALUE);\n    }\n\n    /**\n     * Create a sequence with a specified initial value.\n     *\n     * @param initialValue The initial value for this sequence.\n     */\n    public SequenceVarHandleArray(final long initialValue)\n    {\n        this.set(initialValue);\n    }\n\n    /**\n     * Perform a volatile read of this sequence's value.\n     *\n     * @return The current value of the sequence.\n     */\n    public long get()\n    {\n        return (long) VALUE_FIELD.getAcquire(this.paddedValue, VALUE_INDEX);\n    }\n\n    /**\n     * Perform an ordered write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * store.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void set(final long value)\n    {\n        VALUE_FIELD.setRelease(this.paddedValue, VALUE_INDEX, value);\n    }\n\n    /**\n     * Performs a volatile write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * write and a Store/Load barrier between this write and any\n     * subsequent volatile read.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void setVolatile(final long value)\n    {\n        VALUE_FIELD.setVolatile(this.paddedValue, VALUE_INDEX, value);\n    }\n\n    /**\n     * Perform a compare and set operation on the sequence.\n     *\n     * @param expectedValue The expected current value.\n     * @param newValue The value to update to.\n     * @return true if the operation succeeds, false otherwise.\n     */\n    public boolean compareAndSet(final long expectedValue, final long newValue)\n    {\n        return VALUE_FIELD.compareAndSet(this.paddedValue, VALUE_INDEX, expectedValue, newValue);\n    }\n\n    /**\n     * Atomically increment the sequence by one.\n     *\n     * @return The value after the increment\n     */\n    public long incrementAndGet()\n    {\n        return addAndGet(1L);\n    }\n\n    /**\n     * Atomically add the supplied value.\n     *\n     * @param increment The value to add to the sequence.\n     * @return The value after the increment.\n     */\n    public long addAndGet(final long increment)\n    {\n        return (long) VALUE_FIELD.getAndAdd(this.paddedValue, VALUE_INDEX, increment) + increment;\n    }\n\n    @Override\n    public String toString()\n    {\n        return Long.toString(get());\n    }\n}\n\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/alternatives/SequenceVarHandleBarrier.java",
    "content": "package com.lmax.disruptor.alternatives;\n\n\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.VarHandle;\n\nclass LhsPaddingVarHandleBarrier\n{\n    protected byte\n        p10, p11, p12, p13, p14, p15, p16, p17,\n        p20, p21, p22, p23, p24, p25, p26, p27,\n        p30, p31, p32, p33, p34, p35, p36, p37,\n        p40, p41, p42, p43, p44, p45, p46, p47,\n        p50, p51, p52, p53, p54, p55, p56, p57,\n        p60, p61, p62, p63, p64, p65, p66, p67,\n        p70, p71, p72, p73, p74, p75, p76, p77;\n}\n\nclass ValueVarHandleBarrier extends LhsPaddingVarHandleBarrier\n{\n    protected long value;\n}\n\nclass RhsPaddingVarHandleBarrier extends ValueVarHandleBarrier\n{\n    protected byte\n        p90, p91, p92, p93, p94, p95, p96, p97,\n        p100, p101, p102, p103, p104, p105, p106, p107,\n        p110, p111, p112, p113, p114, p115, p116, p117,\n        p120, p121, p122, p123, p124, p125, p126, p127,\n        p130, p131, p132, p133, p134, p135, p136, p137,\n        p140, p141, p142, p143, p144, p145, p146, p147,\n        p150, p151, p152, p153, p154, p155, p156, p157;\n}\n\n/**\n * Concurrent sequence class used for tracking the progress of\n * the ring buffer and event processors.  Support a number\n * of concurrent operations including CAS and order writes.\n *\n * <p>Also attempts to be more efficient with regards to false\n * sharing by adding padding around the volatile field.\n */\npublic class SequenceVarHandleBarrier extends RhsPaddingVarHandleBarrier\n{\n    static final long INITIAL_VALUE = -1L;\n    private static final VarHandle VALUE_FIELD;\n\n    static\n    {\n        try\n        {\n            VALUE_FIELD = MethodHandles.lookup().in(SequenceVarHandleBarrier.class)\n                    .findVarHandle(SequenceVarHandleBarrier.class, \"value\", long.class);\n        }\n        catch (final Exception e)\n        {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Create a sequence initialised to -1.\n     */\n    public SequenceVarHandleBarrier()\n    {\n        this(INITIAL_VALUE);\n    }\n\n    /**\n     * Create a sequence with a specified initial value.\n     *\n     * @param initialValue The initial value for this sequence.\n     */\n    public SequenceVarHandleBarrier(final long initialValue)\n    {\n        VarHandle.releaseFence();\n        this.value = initialValue;\n    }\n\n    /**\n     * Perform a volatile read of this sequence's value.\n     *\n     * @return The current value of the sequence.\n     */\n    public long get()\n    {\n        long value = this.value;\n        VarHandle.acquireFence();\n        return value;\n    }\n\n    /**\n     * Perform an ordered write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * store.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void set(final long value)\n    {\n        VarHandle.releaseFence();\n        this.value = value;\n    }\n\n    /**\n     * Performs a volatile write of this sequence.  The intent is\n     * a Store/Store barrier between this write and any previous\n     * write and a Store/Load barrier between this write and any\n     * subsequent volatile read.\n     *\n     * @param value The new value for the sequence.\n     */\n    public void setVolatile(final long value)\n    {\n        VarHandle.releaseFence();\n        this.value = value;\n        VarHandle.fullFence();\n    }\n\n    /**\n     * Perform a compare and set operation on the sequence.\n     *\n     * @param expectedValue The expected current value.\n     * @param newValue      The value to update to.\n     * @return true if the operation succeeds, false otherwise.\n     */\n    public boolean compareAndSet(final long expectedValue, final long newValue)\n    {\n        return VALUE_FIELD.compareAndSet(this, expectedValue, newValue);\n    }\n\n    /**\n     * Atomically increment the sequence by one.\n     *\n     * @return The value after the increment\n     */\n    public long incrementAndGet()\n    {\n        return addAndGet(1L);\n    }\n\n    /**\n     * Atomically add the supplied value.\n     *\n     * @param increment The value to add to the sequence.\n     * @return The value after the increment.\n     */\n    public long addAndGet(final long increment)\n    {\n        return (long) VALUE_FIELD.getAndAdd(this, increment) + increment;\n    }\n\n    @Override\n    public String toString()\n    {\n        return Long.toString(get());\n    }\n}"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/dsl/ConsumerRepositoryTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl;\n\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.dsl.stubs.SleepingEventHandler;\nimport com.lmax.disruptor.support.DummyEventProcessor;\nimport com.lmax.disruptor.support.DummySequenceBarrier;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.nullValue;\nimport static org.hamcrest.CoreMatchers.sameInstance;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\npublic class ConsumerRepositoryTest\n{\n    private ConsumerRepository consumerRepository;\n    private EventProcessor eventProcessor1;\n    private EventProcessor eventProcessor2;\n    private SleepingEventHandler handler1;\n    private SleepingEventHandler handler2;\n    private SequenceBarrier barrier1;\n    private SequenceBarrier barrier2;\n\n    @BeforeEach\n    public void setUp()\n    {\n        consumerRepository = new ConsumerRepository();\n        eventProcessor1 = new DummyEventProcessor(new Sequence());\n        eventProcessor2 = new DummyEventProcessor(new Sequence());\n\n        eventProcessor1.run();\n        eventProcessor2.run();\n\n        handler1 = new SleepingEventHandler();\n        handler2 = new SleepingEventHandler();\n\n        barrier1 = new DummySequenceBarrier();\n        barrier2 = new DummySequenceBarrier();\n    }\n\n    @Test\n    public void shouldGetBarrierByHandler()\n    {\n        consumerRepository.add(eventProcessor1, handler1, barrier1);\n\n        assertThat(consumerRepository.getBarrierFor(handler1), sameInstance(barrier1));\n    }\n\n    @Test\n    public void shouldReturnNullForBarrierWhenHandlerIsNotRegistered()\n    {\n        assertThat(consumerRepository.getBarrierFor(handler1), is(nullValue()));\n    }\n\n    @Test\n    public void shouldRetrieveEventProcessorForHandler()\n    {\n        consumerRepository.add(eventProcessor1, handler1, barrier1);\n\n        assertThat(consumerRepository.getEventProcessorFor(handler1), sameInstance(eventProcessor1));\n    }\n\n    @Test\n    public void shouldThrowExceptionWhenHandlerIsNotRegistered()\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n                consumerRepository.getEventProcessorFor(new SleepingEventHandler())\n        );\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/dsl/DisruptorTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl;\n\nimport com.lmax.disruptor.BatchEventProcessor;\nimport com.lmax.disruptor.BatchEventProcessorBuilder;\nimport com.lmax.disruptor.BlockingWaitStrategy;\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.ExceptionHandler;\nimport com.lmax.disruptor.FatalExceptionHandler;\nimport com.lmax.disruptor.RewindableEventHandler;\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.SimpleBatchRewindStrategy;\nimport com.lmax.disruptor.TimeoutException;\nimport com.lmax.disruptor.dsl.stubs.DelayedEventHandler;\nimport com.lmax.disruptor.dsl.stubs.EventHandlerStub;\nimport com.lmax.disruptor.dsl.stubs.EvilEqualsEventHandler;\nimport com.lmax.disruptor.dsl.stubs.ExceptionThrowingEventHandler;\nimport com.lmax.disruptor.dsl.stubs.SleepingEventHandler;\nimport com.lmax.disruptor.dsl.stubs.StubExceptionHandler;\nimport com.lmax.disruptor.dsl.stubs.StubPublisher;\nimport com.lmax.disruptor.dsl.stubs.StubThreadFactory;\nimport com.lmax.disruptor.support.DummyEventHandler;\nimport com.lmax.disruptor.support.TestEvent;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.Timeout;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.concurrent.BrokenBarrierException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.concurrent.locks.LockSupport;\n\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\nimport static java.util.concurrent.TimeUnit.SECONDS;\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertSame;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\n\npublic class DisruptorTest\n{\n    private static final int TIMEOUT_IN_SECONDS = 2;\n\n    public final StubThreadFactory executor = new StubThreadFactory();\n\n    private final Collection<DelayedEventHandler> delayedEventHandlers = new ArrayList<>();\n    private Disruptor<TestEvent> disruptor;\n    private RingBuffer<TestEvent> ringBuffer;\n\n    @BeforeEach\n    public void setUp()\n    {\n        createDisruptor();\n    }\n\n    @AfterEach\n    public void tearDown()\n    {\n        for (DelayedEventHandler delayedEventHandler : delayedEventHandlers)\n        {\n            delayedEventHandler.stopWaiting();\n        }\n\n        disruptor.halt();\n        executor.joinAllThreads();\n    }\n\n    @Test\n    public void shouldHaveStartedAfterStartCalled()\n    {\n        assertFalse(disruptor.hasStarted(), \"Should only be set to started after start is called\");\n\n        disruptor.start();\n\n        assertTrue(disruptor.hasStarted(), \"Should be set to started after start is called\");\n    }\n\n    @Test\n    public void shouldProcessMessagesPublishedBeforeStartIsCalled() throws Exception\n    {\n        final CountDownLatch eventCounter = new CountDownLatch(2);\n        disruptor.handleEventsWith((event, sequence, endOfBatch) -> eventCounter.countDown());\n\n        disruptor.publishEvent((event, sequence) ->\n        {\n        });\n\n        disruptor.start();\n\n        disruptor.publishEvent((event, sequence) ->\n        {\n        });\n\n        if (!eventCounter.await(5, TimeUnit.SECONDS))\n        {\n            fail(\"Did not process event published before start was called. Missed events: \" + eventCounter.getCount());\n        }\n    }\n\n    @Test\n    public void shouldBatchOfEvents() throws Exception\n    {\n        final CountDownLatch eventCounter = new CountDownLatch(2);\n        disruptor.handleEventsWith((event, sequence, endOfBatch) -> eventCounter.countDown());\n\n        disruptor.start();\n\n        disruptor.publishEvents((event, sequence, arg) ->\n        {\n        }, new Object[] { \"a\", \"b\" });\n\n        if (!eventCounter.await(5, TimeUnit.SECONDS))\n        {\n            fail(\"Did not process event published before start was called. Missed events: \" + eventCounter.getCount());\n        }\n    }\n\n    @Test\n    public void shouldHandleEventsWithRewindableEventHandlers() throws Exception\n    {\n        final CountDownLatch eventCounter = new CountDownLatch(2);\n        final RewindableEventHandler<TestEvent> testEventRewindableEventHandler = (event, sequence, endOfBatch) -> eventCounter.countDown();\n        disruptor.handleEventsWith(new SimpleBatchRewindStrategy(), testEventRewindableEventHandler);\n\n        disruptor.start();\n\n        disruptor.publishEvents((event, sequence, arg) ->\n        {\n        }, new Object[] { \"a\", \"b\" });\n\n        if (!eventCounter.await(5, TimeUnit.SECONDS))\n        {\n            fail(\"Did not process event published before start was called. Missed events: \" + eventCounter.getCount());\n        }\n    }\n\n    @Test\n    public void shouldAddEventProcessorsAfterPublishing()\n    {\n        RingBuffer<TestEvent> rb = disruptor.getRingBuffer();\n        BatchEventProcessor<TestEvent> b1 = new BatchEventProcessorBuilder().build(\n                rb, rb.newBarrier(), new SleepingEventHandler());\n        BatchEventProcessor<TestEvent> b2 = new BatchEventProcessorBuilder().build(\n                rb, rb.newBarrier(b1.getSequence()), new SleepingEventHandler());\n        BatchEventProcessor<TestEvent> b3 = new BatchEventProcessorBuilder().build(\n                rb, rb.newBarrier(b2.getSequence()), new SleepingEventHandler());\n\n        assertThat(b1.getSequence().get(), is(-1L));\n        assertThat(b2.getSequence().get(), is(-1L));\n        assertThat(b3.getSequence().get(), is(-1L));\n\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n\n        disruptor.handleEventsWith(b1, b2, b3);\n\n        assertThat(b1.getSequence().get(), is(5L));\n        assertThat(b2.getSequence().get(), is(5L));\n        assertThat(b3.getSequence().get(), is(5L));\n    }\n\n    @Test\n    public void shouldSetSequenceForHandlerIfAddedAfterPublish()\n    {\n        RingBuffer<TestEvent> rb = disruptor.getRingBuffer();\n        EventHandler<TestEvent> b1 = new SleepingEventHandler();\n        EventHandler<TestEvent> b2 = new SleepingEventHandler();\n        EventHandler<TestEvent> b3 = new SleepingEventHandler();\n\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n\n        disruptor.handleEventsWith(b1, b2, b3);\n\n        assertThat(disruptor.getSequenceValueFor(b1), is(5L));\n        assertThat(disruptor.getSequenceValueFor(b2), is(5L));\n        assertThat(disruptor.getSequenceValueFor(b3), is(5L));\n    }\n\n    @Test\n    public void shouldGetSequenceBarrierForHandler()\n    {\n        RingBuffer<TestEvent> rb = disruptor.getRingBuffer();\n        EventHandler<TestEvent> handler = new DummyEventHandler<>();\n\n        disruptor.handleEventsWith(handler);\n        disruptor.start();\n\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n\n        assertThat(disruptor.getBarrierFor(handler).getCursor(), is(5L));\n    }\n\n    @Test\n    public void shouldGetSequenceBarrierForHandlerIfAddedAfterPublish()\n    {\n        RingBuffer<TestEvent> rb = disruptor.getRingBuffer();\n        EventHandler<TestEvent> handler = new DummyEventHandler<>();\n\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n        rb.publish(rb.next());\n\n        disruptor.handleEventsWith(handler);\n        disruptor.start();\n\n        assertThat(disruptor.getBarrierFor(handler).getCursor(), is(5L));\n    }\n\n    @Test\n    public void shouldCreateEventProcessorGroupForFirstEventProcessors()\n    {\n        executor.ignoreExecutions();\n        final EventHandler<TestEvent> eventHandler1 = new SleepingEventHandler();\n        EventHandler<TestEvent> eventHandler2 = new SleepingEventHandler();\n\n        final EventHandlerGroup<TestEvent> eventHandlerGroup =\n            disruptor.handleEventsWith(eventHandler1, eventHandler2);\n        disruptor.start();\n\n        assertNotNull(eventHandlerGroup);\n        assertThat(executor.getExecutionCount(), equalTo(2));\n    }\n\n    @Test\n    public void shouldMakeEntriesAvailableToFirstHandlersImmediately() throws Exception\n    {\n        CountDownLatch countDownLatch = new CountDownLatch(2);\n        EventHandler<TestEvent> eventHandler = new EventHandlerStub<>(countDownLatch);\n\n        disruptor.handleEventsWith(createDelayedEventHandler(), eventHandler);\n\n        ensureTwoEventsProcessedAccordingToDependencies(countDownLatch);\n    }\n\n    @Test\n    public void shouldWaitUntilAllFirstEventProcessorsProcessEventBeforeMakingItAvailableToDependentEventProcessors()\n        throws Exception\n    {\n        DelayedEventHandler eventHandler1 = createDelayedEventHandler();\n\n        CountDownLatch countDownLatch = new CountDownLatch(2);\n        EventHandler<TestEvent> eventHandler2 = new EventHandlerStub<>(countDownLatch);\n\n        disruptor.handleEventsWith(eventHandler1).then(eventHandler2);\n\n        ensureTwoEventsProcessedAccordingToDependencies(countDownLatch, eventHandler1);\n    }\n\n    @Test\n    public void shouldSupportAddingCustomEventProcessorWithFactory()\n    {\n        RingBuffer<TestEvent> rb = disruptor.getRingBuffer();\n        BatchEventProcessor<TestEvent> b1 = new BatchEventProcessorBuilder().build(\n                rb, rb.newBarrier(), new SleepingEventHandler());\n        EventProcessorFactory<TestEvent> b2 = (ringBuffer, barrierSequences) -> new BatchEventProcessorBuilder().build(\n                ringBuffer, ringBuffer.newBarrier(barrierSequences), new SleepingEventHandler());\n\n        disruptor.handleEventsWith(b1).then(b2);\n\n        disruptor.start();\n\n        assertThat(executor.getExecutionCount(), equalTo(2));\n    }\n\n    @Test\n    public void shouldAllowSpecifyingSpecificEventProcessorsToWaitFor()\n        throws Exception\n    {\n        DelayedEventHandler handler1 = createDelayedEventHandler();\n        DelayedEventHandler handler2 = createDelayedEventHandler();\n\n        CountDownLatch countDownLatch = new CountDownLatch(2);\n        EventHandler<TestEvent> handlerWithBarrier = new EventHandlerStub<>(countDownLatch);\n\n        disruptor.handleEventsWith(handler1, handler2);\n        disruptor.after(handler1, handler2).handleEventsWith(handlerWithBarrier);\n\n        ensureTwoEventsProcessedAccordingToDependencies(countDownLatch, handler1, handler2);\n\n        assertThat(executor.getExecutionCount(), equalTo(3));\n    }\n\n    @Test\n    public void shouldWaitOnAllProducersJoinedByAnd()\n        throws Exception\n    {\n        DelayedEventHandler handler1 = createDelayedEventHandler();\n        DelayedEventHandler handler2 = createDelayedEventHandler();\n\n        CountDownLatch countDownLatch = new CountDownLatch(2);\n        EventHandler<TestEvent> handlerWithBarrier = new EventHandlerStub<>(countDownLatch);\n\n        disruptor.handleEventsWith(handler1);\n        final EventHandlerGroup<TestEvent> handler2Group = disruptor.handleEventsWith(handler2);\n        disruptor.after(handler1).and(handler2Group).handleEventsWith(handlerWithBarrier);\n\n        ensureTwoEventsProcessedAccordingToDependencies(countDownLatch, handler1, handler2);\n\n        assertThat(executor.getExecutionCount(), equalTo(3));\n    }\n\n    @Test\n    public void shouldThrowExceptionIfHandlerIsNotAlreadyConsuming()\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n                disruptor.after(createDelayedEventHandler()).handleEventsWith(createDelayedEventHandler()));\n    }\n\n    @Test\n    public void shouldTrackEventHandlersByIdentityNotEquality()\n    {\n        assertThrows(IllegalArgumentException.class, () ->\n        {\n            EvilEqualsEventHandler handler1 = new EvilEqualsEventHandler();\n            EvilEqualsEventHandler handler2 = new EvilEqualsEventHandler();\n\n            disruptor.handleEventsWith(handler1);\n\n            // handler2.equals(handler1) but it hasn't yet been registered so should throw exception.\n            disruptor.after(handler2);\n        });\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Test\n    public void shouldSupportSpecifyingAExceptionHandlerForEventProcessors()\n        throws Exception\n    {\n        AtomicReference<Throwable> eventHandled = new AtomicReference<>();\n        ExceptionHandler<Object> exceptionHandler = new StubExceptionHandler(eventHandled);\n        RuntimeException testException = new RuntimeException();\n        ExceptionThrowingEventHandler handler = new ExceptionThrowingEventHandler(testException);\n\n        disruptor.handleExceptionsWith(exceptionHandler);\n        disruptor.handleEventsWith(handler);\n\n        publishEvent();\n\n        final Throwable actualException = waitFor(eventHandled);\n        assertSame(testException, actualException);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Test\n    public void shouldOnlyApplyExceptionsHandlersSpecifiedViaHandleExceptionsWithOnNewEventProcessors()\n        throws Exception\n    {\n        AtomicReference<Throwable> eventHandled = new AtomicReference<>();\n        ExceptionHandler<Object> exceptionHandler = new StubExceptionHandler(eventHandled);\n        RuntimeException testException = new RuntimeException();\n        ExceptionThrowingEventHandler handler = new ExceptionThrowingEventHandler(testException);\n\n        disruptor.handleExceptionsWith(exceptionHandler);\n        disruptor.handleEventsWith(handler);\n        disruptor.handleExceptionsWith(new FatalExceptionHandler());\n\n        publishEvent();\n\n        final Throwable actualException = waitFor(eventHandled);\n        assertSame(testException, actualException);\n    }\n\n    @Test\n    public void shouldSupportSpecifyingADefaultExceptionHandlerForEventProcessors()\n        throws Exception\n    {\n        AtomicReference<Throwable> eventHandled = new AtomicReference<>();\n        ExceptionHandler<Object> exceptionHandler = new StubExceptionHandler(eventHandled);\n        RuntimeException testException = new RuntimeException();\n        ExceptionThrowingEventHandler handler = new ExceptionThrowingEventHandler(testException);\n\n        disruptor.setDefaultExceptionHandler(exceptionHandler);\n        disruptor.handleEventsWith(handler);\n\n        publishEvent();\n\n        final Throwable actualException = waitFor(eventHandled);\n        assertSame(testException, actualException);\n    }\n\n    @Test\n    public void shouldApplyDefaultExceptionHandlerToExistingEventProcessors()\n        throws Exception\n    {\n        AtomicReference<Throwable> eventHandled = new AtomicReference<>();\n        ExceptionHandler<Object> exceptionHandler = new StubExceptionHandler(eventHandled);\n        RuntimeException testException = new RuntimeException();\n        ExceptionThrowingEventHandler handler = new ExceptionThrowingEventHandler(testException);\n\n        disruptor.handleEventsWith(handler);\n        disruptor.setDefaultExceptionHandler(exceptionHandler);\n\n        publishEvent();\n\n        final Throwable actualException = waitFor(eventHandled);\n        assertSame(testException, actualException);\n    }\n\n    @Test\n    public void shouldBlockProducerUntilAllEventProcessorsHaveAdvanced()\n        throws Exception\n    {\n        final DelayedEventHandler delayedEventHandler = createDelayedEventHandler();\n        disruptor.handleEventsWith(delayedEventHandler);\n\n        final RingBuffer<TestEvent> ringBuffer = disruptor.start();\n        delayedEventHandler.awaitStart();\n\n        final StubPublisher stubPublisher = new StubPublisher(ringBuffer);\n        try\n        {\n            executor.newThread(stubPublisher).start();\n\n            assertProducerReaches(stubPublisher, 4, true);\n\n            delayedEventHandler.processEvent();\n            delayedEventHandler.processEvent();\n            delayedEventHandler.processEvent();\n            delayedEventHandler.processEvent();\n            delayedEventHandler.processEvent();\n\n            assertProducerReaches(stubPublisher, 5, false);\n        }\n        finally\n        {\n            stubPublisher.halt();\n        }\n    }\n\n    @Test\n    public void shouldBeAbleToOverrideTheExceptionHandlerForAEventProcessor()\n        throws Exception\n    {\n        final RuntimeException testException = new RuntimeException();\n        final ExceptionThrowingEventHandler eventHandler = new ExceptionThrowingEventHandler(testException);\n        disruptor.handleEventsWith(eventHandler);\n\n        AtomicReference<Throwable> reference = new AtomicReference<>();\n        StubExceptionHandler exceptionHandler = new StubExceptionHandler(reference);\n        disruptor.handleExceptionsFor(eventHandler).with(exceptionHandler);\n\n        publishEvent();\n\n        final Throwable actualException = waitFor(reference);\n        assertSame(testException, actualException);\n    }\n\n    @Test\n    public void shouldThrowExceptionWhenAddingEventProcessorsAfterTheProducerBarrierHasBeenCreated()\n    {\n        assertThrows(IllegalStateException.class, () ->\n        {\n            executor.ignoreExecutions();\n            disruptor.handleEventsWith(new SleepingEventHandler());\n            disruptor.start();\n            disruptor.handleEventsWith(new SleepingEventHandler());\n        });\n    }\n\n    @Test\n    public void shouldThrowExceptionIfStartIsCalledTwice()\n    {\n        assertThrows(IllegalStateException.class, () ->\n        {\n            executor.ignoreExecutions();\n            disruptor.handleEventsWith(new SleepingEventHandler());\n            disruptor.start();\n            disruptor.start();\n        });\n    }\n\n    @Test\n    public void shouldSupportCustomProcessorsAsDependencies()\n        throws Exception\n    {\n        RingBuffer<TestEvent> ringBuffer = disruptor.getRingBuffer();\n\n        final DelayedEventHandler delayedEventHandler = createDelayedEventHandler();\n\n        CountDownLatch countDownLatch = new CountDownLatch(2);\n        EventHandler<TestEvent> handlerWithBarrier = new EventHandlerStub<>(countDownLatch);\n\n        final BatchEventProcessor<TestEvent> processor =\n                new BatchEventProcessorBuilder().build(ringBuffer, ringBuffer.newBarrier(), delayedEventHandler);\n\n        disruptor.handleEventsWith(processor).then(handlerWithBarrier);\n\n        ensureTwoEventsProcessedAccordingToDependencies(countDownLatch, delayedEventHandler);\n\n        assertThat(executor.getExecutionCount(), equalTo(2));\n    }\n\n    @Test\n    public void shouldSupportHandlersAsDependenciesToCustomProcessors()\n        throws Exception\n    {\n        final DelayedEventHandler delayedEventHandler = createDelayedEventHandler();\n        disruptor.handleEventsWith(delayedEventHandler);\n\n\n        RingBuffer<TestEvent> ringBuffer = disruptor.getRingBuffer();\n        CountDownLatch countDownLatch = new CountDownLatch(2);\n        EventHandler<TestEvent> handlerWithBarrier = new EventHandlerStub<>(countDownLatch);\n\n        final SequenceBarrier sequenceBarrier = disruptor.after(delayedEventHandler).asSequenceBarrier();\n        final BatchEventProcessor<TestEvent> processor =\n                new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, handlerWithBarrier);\n        disruptor.handleEventsWith(processor);\n\n        ensureTwoEventsProcessedAccordingToDependencies(countDownLatch, delayedEventHandler);\n\n        assertThat(executor.getExecutionCount(), equalTo(2));\n    }\n\n    @Test\n    public void shouldSupportCustomProcessorsAndHandlersAsDependencies() throws Exception\n    {\n        final DelayedEventHandler delayedEventHandler1 = createDelayedEventHandler();\n        final DelayedEventHandler delayedEventHandler2 = createDelayedEventHandler();\n        disruptor.handleEventsWith(delayedEventHandler1);\n\n\n        RingBuffer<TestEvent> ringBuffer = disruptor.getRingBuffer();\n        CountDownLatch countDownLatch = new CountDownLatch(2);\n        EventHandler<TestEvent> handlerWithBarrier = new EventHandlerStub<>(countDownLatch);\n\n        final SequenceBarrier sequenceBarrier = disruptor.after(delayedEventHandler1).asSequenceBarrier();\n        final BatchEventProcessor<TestEvent> processor =\n                new BatchEventProcessorBuilder().build(ringBuffer, sequenceBarrier, delayedEventHandler2);\n\n        disruptor.after(delayedEventHandler1).and(processor).handleEventsWith(handlerWithBarrier);\n\n        ensureTwoEventsProcessedAccordingToDependencies(countDownLatch, delayedEventHandler1, delayedEventHandler2);\n\n        assertThat(executor.getExecutionCount(), equalTo(3));\n    }\n\n    @Test\n    public void shouldSupportMultipleCustomProcessorsAsDependencies() throws Exception\n    {\n        final RingBuffer<TestEvent> ringBuffer = disruptor.getRingBuffer();\n        final CountDownLatch countDownLatch = new CountDownLatch(2);\n        final EventHandler<TestEvent> handlerWithBarrier = new EventHandlerStub<>(countDownLatch);\n\n        final DelayedEventHandler delayedEventHandler1 = createDelayedEventHandler();\n        final BatchEventProcessor<TestEvent> processor1 =\n                new BatchEventProcessorBuilder().build(ringBuffer, ringBuffer.newBarrier(), delayedEventHandler1);\n\n        final DelayedEventHandler delayedEventHandler2 = createDelayedEventHandler();\n        final BatchEventProcessor<TestEvent> processor2 =\n                new BatchEventProcessorBuilder().build(ringBuffer, ringBuffer.newBarrier(), delayedEventHandler2);\n\n        disruptor.handleEventsWith(processor1, processor2);\n        disruptor.after(processor1, processor2).handleEventsWith(handlerWithBarrier);\n\n        ensureTwoEventsProcessedAccordingToDependencies(countDownLatch, delayedEventHandler1, delayedEventHandler2);\n        assertThat(executor.getExecutionCount(), equalTo(3));\n    }\n\n    @Test\n    @Timeout(value = 2000, unit = MILLISECONDS)\n    public void shouldThrowTimeoutExceptionIfShutdownDoesNotCompleteNormally()\n    {\n        assertThrows(TimeoutException.class, () ->\n        {\n            //Given\n            final DelayedEventHandler delayedEventHandler = createDelayedEventHandler();\n            disruptor.handleEventsWith(delayedEventHandler);\n            publishEvent();\n            //Then\n            disruptor.shutdown(1, SECONDS);\n        });\n    }\n\n    @Test\n    @Timeout(value = 1, unit = SECONDS)\n    public void shouldTrackRemainingCapacity() throws Exception\n    {\n        final long[] remainingCapacity = {-1};\n        //Given\n        final EventHandler<TestEvent> eventHandler = (event, sequence, endOfBatch) ->\n                remainingCapacity[0] = disruptor.getRingBuffer().remainingCapacity();\n\n        disruptor.handleEventsWith(eventHandler);\n\n        //When\n        publishEvent();\n\n        //Then\n        while (remainingCapacity[0] == -1)\n        {\n            LockSupport.parkNanos(MILLISECONDS.toNanos(100));\n        }\n        assertThat(remainingCapacity[0], is(ringBuffer.getBufferSize() - 1L));\n        assertThat(disruptor.getRingBuffer().remainingCapacity(), is((long) ringBuffer.getBufferSize()));\n    }\n\n    @Test\n    public void shouldAllowEventHandlerWithSuperType() throws Exception\n    {\n        final CountDownLatch latch = new CountDownLatch(2);\n        final EventHandler<Object> objectHandler = new EventHandlerStub<>(latch);\n\n        disruptor.handleEventsWith(objectHandler);\n\n        ensureTwoEventsProcessedAccordingToDependencies(latch);\n    }\n\n    @Test\n    public void shouldAllowChainingEventHandlersWithSuperType() throws Exception\n    {\n        final CountDownLatch latch = new CountDownLatch(2);\n        final DelayedEventHandler delayedEventHandler = createDelayedEventHandler();\n        final EventHandler<Object> objectHandler = new EventHandlerStub<>(latch);\n\n        disruptor.handleEventsWith(delayedEventHandler).then(objectHandler);\n\n        ensureTwoEventsProcessedAccordingToDependencies(latch, delayedEventHandler);\n    }\n\n    @Test\n    public void shouldMakeEntriesAvailableToFirstCustomProcessorsImmediately() throws Exception\n    {\n        final CountDownLatch countDownLatch = new CountDownLatch(2);\n        final EventHandler<TestEvent> eventHandler = new EventHandlerStub<>(countDownLatch);\n\n        disruptor.handleEventsWith(\n                (EventProcessorFactory<TestEvent>) (ringBuffer, barrierSequences) ->\n                {\n                    assertEquals(0, barrierSequences.length,\n                            \"Should not have had any barrier sequences\");\n                    return new BatchEventProcessorBuilder().build(\n                            disruptor.getRingBuffer(), ringBuffer.newBarrier(\n                            barrierSequences), eventHandler);\n                });\n\n        ensureTwoEventsProcessedAccordingToDependencies(countDownLatch);\n    }\n\n    @Test\n    public void shouldHonourDependenciesForCustomProcessors() throws Exception\n    {\n        final CountDownLatch countDownLatch = new CountDownLatch(2);\n        final EventHandler<TestEvent> eventHandler = new EventHandlerStub<>(countDownLatch);\n        final DelayedEventHandler delayedEventHandler = createDelayedEventHandler();\n\n        final EventProcessorFactory<TestEvent> eventProcessorFactory = (ringBuffer, barrierSequences) ->\n        {\n            assertSame(1, barrierSequences.length, \"Should have had a barrier sequence\");\n            return new BatchEventProcessorBuilder().build(\n                    disruptor.getRingBuffer(), ringBuffer.newBarrier(\n                            barrierSequences), eventHandler);\n        };\n        disruptor.handleEventsWith(delayedEventHandler)\n                .then(eventProcessorFactory);\n\n        ensureTwoEventsProcessedAccordingToDependencies(countDownLatch, delayedEventHandler);\n    }\n\n    private void ensureTwoEventsProcessedAccordingToDependencies(\n        final CountDownLatch countDownLatch,\n        final DelayedEventHandler... dependencies)\n        throws InterruptedException, BrokenBarrierException\n    {\n        publishEvent();\n        publishEvent();\n\n        for (DelayedEventHandler dependency : dependencies)\n        {\n            assertThatCountDownLatchEquals(countDownLatch, 2L);\n            dependency.processEvent();\n            dependency.processEvent();\n        }\n\n        assertThatCountDownLatchIsZero(countDownLatch);\n    }\n\n    private void assertProducerReaches(\n        final StubPublisher stubPublisher,\n        final int expectedPublicationCount,\n        final boolean strict)\n    {\n        long loopStart = System.currentTimeMillis();\n        while (stubPublisher.getPublicationCount() < expectedPublicationCount && System\n            .currentTimeMillis() - loopStart < 5000)\n        {\n            Thread.yield();\n        }\n\n        if (strict)\n        {\n            assertThat(stubPublisher.getPublicationCount(), equalTo(expectedPublicationCount));\n        }\n        else\n        {\n            final int actualPublicationCount = stubPublisher.getPublicationCount();\n            final String msg = \"Producer reached unexpected count. Expected at least \" + expectedPublicationCount +\n                    \" but only reached \" + actualPublicationCount;\n            assertTrue(actualPublicationCount >= expectedPublicationCount, msg);\n        }\n    }\n\n    private void createDisruptor()\n    {\n        disruptor = new Disruptor<>(\n                TestEvent.EVENT_FACTORY,\n                4,\n                executor,\n                ProducerType.SINGLE,\n                new BlockingWaitStrategy());\n    }\n\n    private void publishEvent() throws InterruptedException, BrokenBarrierException\n    {\n        if (ringBuffer == null)\n        {\n            ringBuffer = disruptor.start();\n\n            for (DelayedEventHandler eventHandler : delayedEventHandlers)\n            {\n                eventHandler.awaitStart();\n            }\n        }\n\n        disruptor.publishEvent((event, sequence) ->\n        {\n        });\n    }\n\n    private Throwable waitFor(final AtomicReference<Throwable> reference)\n    {\n        while (reference.get() == null)\n        {\n            Thread.yield();\n        }\n\n        return reference.get();\n    }\n\n    private DelayedEventHandler createDelayedEventHandler()\n    {\n        final DelayedEventHandler delayedEventHandler = new DelayedEventHandler();\n        delayedEventHandlers.add(delayedEventHandler);\n        return delayedEventHandler;\n    }\n\n    @SuppressWarnings(\"SameParameterValue\")\n    private void assertThatCountDownLatchEquals(\n        final CountDownLatch countDownLatch,\n        final long expectedCountDownValue)\n    {\n        assertThat(countDownLatch.getCount(), equalTo(expectedCountDownValue));\n    }\n\n    private void assertThatCountDownLatchIsZero(final CountDownLatch countDownLatch)\n        throws InterruptedException\n    {\n        boolean released = countDownLatch.await(TIMEOUT_IN_SECONDS, SECONDS);\n        assertTrue(released, \"Batch handler did not receive entries: \" + countDownLatch.getCount());\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/dsl/stubs/DelayedEventHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl.stubs;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.support.TestEvent;\n\nimport java.util.concurrent.BrokenBarrierException;\nimport java.util.concurrent.CyclicBarrier;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class DelayedEventHandler implements EventHandler<TestEvent>\n{\n    private final AtomicBoolean readyToProcessEvent = new AtomicBoolean(false);\n    private volatile boolean stopped = false;\n    private final CyclicBarrier barrier;\n\n    public DelayedEventHandler(final CyclicBarrier barrier)\n    {\n        this.barrier = barrier;\n    }\n\n    public DelayedEventHandler()\n    {\n        this(new CyclicBarrier(2));\n    }\n\n    @Override\n    public void onEvent(final TestEvent entry, final long sequence, final boolean endOfBatch) throws Exception\n    {\n        waitForAndSetFlag(false);\n    }\n\n    public void processEvent()\n    {\n        waitForAndSetFlag(true);\n    }\n\n    public void stopWaiting()\n    {\n        stopped = true;\n    }\n\n    private void waitForAndSetFlag(final boolean newValue)\n    {\n        while (!stopped && !Thread.currentThread().isInterrupted() &&\n            !readyToProcessEvent.compareAndSet(!newValue, newValue))\n        {\n            Thread.yield();\n        }\n    }\n\n    @Override\n    public void onStart()\n    {\n        try\n        {\n            barrier.await();\n        }\n        catch (InterruptedException e)\n        {\n            throw new RuntimeException(e);\n        }\n        catch (BrokenBarrierException e)\n        {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public void onShutdown()\n    {\n    }\n\n    public void awaitStart() throws InterruptedException, BrokenBarrierException\n    {\n        barrier.await();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/dsl/stubs/EventHandlerStub.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl.stubs;\n\nimport com.lmax.disruptor.EventHandler;\n\nimport java.util.concurrent.CountDownLatch;\n\npublic class EventHandlerStub<T> implements EventHandler<T>\n{\n    private final CountDownLatch countDownLatch;\n\n    public EventHandlerStub(final CountDownLatch countDownLatch)\n    {\n        this.countDownLatch = countDownLatch;\n    }\n\n    @Override\n    public void onEvent(final T entry, final long sequence, final boolean endOfBatch) throws Exception\n    {\n        countDownLatch.countDown();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/dsl/stubs/EvilEqualsEventHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl.stubs;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.support.TestEvent;\n\npublic class EvilEqualsEventHandler implements EventHandler<TestEvent>\n{\n    @Override\n    public void onEvent(final TestEvent entry, final long sequence, final boolean endOfBatch) throws Exception\n    {\n    }\n\n    @SuppressWarnings({\"EqualsWhichDoesntCheckParameterClass\"})\n    public boolean equals(final Object o)\n    {\n        return true;\n    }\n\n    public int hashCode()\n    {\n        return 1;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/dsl/stubs/ExceptionThrowingEventHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl.stubs;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.support.TestEvent;\n\npublic class ExceptionThrowingEventHandler implements EventHandler<TestEvent>\n{\n    private final RuntimeException testException;\n\n    public ExceptionThrowingEventHandler(final RuntimeException testException)\n    {\n        this.testException = testException;\n    }\n\n    @Override\n    public void onEvent(final TestEvent entry, final long sequence, final boolean endOfBatch) throws Exception\n    {\n        throw testException;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/dsl/stubs/SleepingEventHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl.stubs;\n\nimport com.lmax.disruptor.EventHandler;\nimport com.lmax.disruptor.support.TestEvent;\n\npublic class SleepingEventHandler implements EventHandler<TestEvent>\n{\n    @Override\n    public void onEvent(final TestEvent entry, final long sequence, final boolean endOfBatch) throws Exception\n    {\n        Thread.sleep(1000);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/dsl/stubs/StubExceptionHandler.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl.stubs;\n\nimport com.lmax.disruptor.ExceptionHandler;\n\nimport java.util.concurrent.atomic.AtomicReference;\n\npublic class StubExceptionHandler implements ExceptionHandler<Object>\n{\n    private final AtomicReference<Throwable> exceptionHandled;\n\n    public StubExceptionHandler(final AtomicReference<Throwable> exceptionHandled)\n    {\n        this.exceptionHandled = exceptionHandled;\n    }\n\n    @Override\n    public void handleEventException(final Throwable ex, final long sequence, final Object event)\n    {\n        exceptionHandled.set(ex);\n    }\n\n    @Override\n    public void handleOnStartException(final Throwable ex)\n    {\n        exceptionHandled.set(ex);\n    }\n\n    @Override\n    public void handleOnShutdownException(final Throwable ex)\n    {\n        exceptionHandled.set(ex);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/dsl/stubs/StubPublisher.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl.stubs;\n\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.support.TestEvent;\n\npublic class StubPublisher implements Runnable\n{\n    private volatile boolean running = true;\n    private volatile int publicationCount = 0;\n\n    private final RingBuffer<TestEvent> ringBuffer;\n\n    public StubPublisher(final RingBuffer<TestEvent> ringBuffer)\n    {\n        this.ringBuffer = ringBuffer;\n    }\n\n    public void run()\n    {\n        while (running)\n        {\n            final long sequence = ringBuffer.next();\n            //final TestEvent entry = ringBuffer.get(sequence);\n            ringBuffer.publish(sequence);\n            publicationCount++;\n        }\n    }\n\n    public int getPublicationCount()\n    {\n        return publicationCount;\n    }\n\n    public void halt()\n    {\n        running = false;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/dsl/stubs/StubThreadFactory.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.dsl.stubs;\n\nimport com.lmax.disruptor.util.DaemonThreadFactory;\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.logging.Logger;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\n\npublic final class StubThreadFactory implements ThreadFactory, AfterEachCallback\n{\n    private static final Logger LOGGER = Logger.getLogger(StubThreadFactory.class.getName());\n\n    private final DaemonThreadFactory threadFactory = DaemonThreadFactory.INSTANCE;\n    private final Collection<Thread> threads = new CopyOnWriteArrayList<>();\n    private final AtomicBoolean ignoreExecutions = new AtomicBoolean(false);\n    private final AtomicInteger executionCount = new AtomicInteger(0);\n    private final List<Throwable> threadErrors = Collections.synchronizedList(new ArrayList<>());\n    private final List<IgnoredException> ignoredExceptions = new ArrayList<>();\n\n    @Override\n    public Thread newThread(final Runnable command)\n    {\n        executionCount.getAndIncrement();\n        Runnable toExecute = () ->\n        {\n            try\n            {\n                command.run();\n            }\n            catch (Throwable t)\n            {\n                threadErrors.add(t);\n            }\n        };\n        if (ignoreExecutions.get())\n        {\n            toExecute = new NoOpRunnable();\n        }\n        final Thread thread = threadFactory.newThread(toExecute);\n        thread.setName(command.toString());\n        threads.add(thread);\n        return thread;\n    }\n\n    public void joinAllThreads()\n    {\n        for (Thread thread : threads)\n        {\n            if (thread.isAlive())\n            {\n                try\n                {\n                    thread.interrupt();\n                    thread.join(5000);\n                }\n                catch (InterruptedException e)\n                {\n                    e.printStackTrace();\n                }\n            }\n\n            assertFalse(thread.isAlive(), \"Failed to stop thread: \" + thread);\n        }\n\n        threads.clear();\n    }\n\n    public void ignoreExecutions()\n    {\n        ignoreExecutions.set(true);\n    }\n\n    public int getExecutionCount()\n    {\n        return executionCount.get();\n    }\n\n    @Override\n    public void afterEach(final ExtensionContext context) throws Exception\n    {\n        if (!threadErrors.isEmpty())\n        {\n            for (final Throwable threadError : threadErrors)\n            {\n                boolean ignored = false;\n                for (final IgnoredException ignoredException : ignoredExceptions)\n                {\n                    if (threadError.getMessage().equalsIgnoreCase(ignoredException.exceptionMessage))\n                    {\n                        LOGGER.info(\"Ignoring '\" + threadError.getMessage() + \"' \" +\n                                \"because: \" + ignoredException.reason);\n                        ignored = true;\n                        break;\n                    }\n                }\n                if (!ignored)\n                {\n                    throw new Exception(threadError);\n                }\n            }\n        }\n    }\n\n    private static final class IgnoredException\n    {\n        final String exceptionMessage;\n        final String reason;\n\n        IgnoredException(final String exceptionMessage, final String reason)\n        {\n            this.exceptionMessage = exceptionMessage;\n            this.reason = reason;\n        }\n    }\n\n    private static final class NoOpRunnable implements Runnable\n    {\n        @Override\n        public void run()\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/support/DummyEventHandler.java",
    "content": "package com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventHandler;\n\npublic class DummyEventHandler<T> implements EventHandler<T>\n{\n    public int startCalls = 0;\n    public int shutdownCalls = 0;\n    public T lastEvent;\n    public long lastSequence;\n\n    @Override\n    public void onStart()\n    {\n        startCalls++;\n    }\n\n    @Override\n    public void onShutdown()\n    {\n        shutdownCalls++;\n    }\n\n    @Override\n    public void onEvent(final T event, final long sequence, final boolean endOfBatch) throws Exception\n    {\n        lastEvent = event;\n        lastSequence = sequence;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/support/DummyEventProcessor.java",
    "content": "package com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventProcessor;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SingleProducerSequencer;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class DummyEventProcessor implements EventProcessor\n{\n    private final Sequence sequence;\n    private final AtomicBoolean running = new AtomicBoolean(false);\n\n    public DummyEventProcessor(final Sequence sequence)\n    {\n        this.sequence = sequence;\n    }\n\n    public DummyEventProcessor()\n    {\n        this(new Sequence(SingleProducerSequencer.INITIAL_CURSOR_VALUE));\n    }\n\n    public void setSequence(final long sequence)\n    {\n        this.sequence.set(sequence);\n    }\n\n    @Override\n    public Sequence getSequence()\n    {\n        return sequence;\n    }\n\n    @Override\n    public void halt()\n    {\n        running.set(false);\n    }\n\n    @Override\n    public boolean isRunning()\n    {\n        return running.get();\n    }\n\n    @Override\n    public void run()\n    {\n        if (!running.compareAndSet(false, true))\n        {\n            throw new IllegalStateException(\"Already running\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/support/DummySequenceBarrier.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\n\nimport com.lmax.disruptor.AlertException;\nimport com.lmax.disruptor.SequenceBarrier;\n\npublic class DummySequenceBarrier implements SequenceBarrier\n{\n    @Override\n    public long waitFor(final long sequence) throws AlertException, InterruptedException\n    {\n        return 0;\n    }\n\n    @Override\n    public long getCursor()\n    {\n        return 0;\n    }\n\n    @Override\n    public boolean isAlerted()\n    {\n        return false;\n    }\n\n    @Override\n    public void alert()\n    {\n    }\n\n    @Override\n    public void clearAlert()\n    {\n    }\n\n    @Override\n    public void checkAlert() throws AlertException\n    {\n    }\n}"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/support/DummyWaitStrategy.java",
    "content": "package com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.AlertException;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.SequenceBarrier;\nimport com.lmax.disruptor.TimeoutException;\nimport com.lmax.disruptor.WaitStrategy;\n\npublic class DummyWaitStrategy implements WaitStrategy\n{\n    public int signalAllWhenBlockingCalls = 0;\n\n    @Override\n    public long waitFor(\n            final long sequence, final Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier)\n        throws AlertException, InterruptedException, TimeoutException\n    {\n        return 0;\n    }\n\n    @Override\n    public void signalAllWhenBlocking()\n    {\n        signalAllWhenBlockingCalls++;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/support/LongEvent.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventFactory;\n\npublic class LongEvent\n{\n    private long value;\n\n    public void set(final long value)\n    {\n        this.value = value;\n    }\n\n    public long get()\n    {\n        return value;\n    }\n\n    public static final EventFactory<LongEvent> FACTORY = () -> new LongEvent();\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/support/SequenceUpdater.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.WaitStrategy;\n\nimport java.util.concurrent.BrokenBarrierException;\nimport java.util.concurrent.CyclicBarrier;\n\nclass SequenceUpdater implements Runnable\n{\n    public final Sequence sequence = new Sequence();\n    private final CyclicBarrier barrier = new CyclicBarrier(2);\n    private final long sleepTime;\n    private final WaitStrategy waitStrategy;\n\n    SequenceUpdater(final long sleepTime, final WaitStrategy waitStrategy)\n    {\n        this.sleepTime = sleepTime;\n        this.waitStrategy = waitStrategy;\n    }\n\n    @Override\n    public void run()\n    {\n        try\n        {\n            barrier.await();\n            if (0 != sleepTime)\n            {\n                Thread.sleep(sleepTime);\n            }\n            sequence.incrementAndGet();\n            waitStrategy.signalAllWhenBlocking();\n        }\n        catch (Exception e)\n        {\n            e.printStackTrace();\n        }\n    }\n\n    public void waitForStartup() throws InterruptedException, BrokenBarrierException\n    {\n        barrier.await();\n    }\n}"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/support/StubEvent.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventFactory;\nimport com.lmax.disruptor.EventTranslatorTwoArg;\n\npublic final class StubEvent\n{\n    private int value;\n    private String testString;\n    public static final EventTranslatorTwoArg<StubEvent, Integer, String> TRANSLATOR = (event, sequence, arg0, arg1) ->\n            {\n                event.setValue(arg0);\n                event.setTestString(arg1);\n            };\n\n    public StubEvent(final int i)\n    {\n        this.value = i;\n    }\n\n    public void copy(final StubEvent event)\n    {\n        value = event.value;\n    }\n\n    public int getValue()\n    {\n        return value;\n    }\n\n    public void setValue(final int value)\n    {\n        this.value = value;\n    }\n\n    public String getTestString()\n    {\n        return testString;\n    }\n\n    public void setTestString(final String testString)\n    {\n        this.testString = testString;\n    }\n\n    public static final EventFactory<StubEvent> EVENT_FACTORY = () -> new StubEvent(-1);\n\n    @Override\n    public boolean equals(final Object o)\n    {\n        if (this == o)\n        {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass())\n        {\n            return false;\n        }\n\n        final StubEvent stubEvent = (StubEvent) o;\n\n        if (value != stubEvent.value)\n        {\n            return false;\n        }\n        return testString != null ? testString.equals(stubEvent.testString) : stubEvent.testString == null;\n    }\n\n    @Override\n    public int hashCode()\n    {\n        int result = value;\n        result = 31 * result + (testString != null ? testString.hashCode() : 0);\n        return result;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/support/TestEvent.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.EventFactory;\n\npublic final class TestEvent\n{\n    @Override\n    public String toString()\n    {\n        return \"Test Event\";\n    }\n\n    public static final EventFactory<TestEvent> EVENT_FACTORY = TestEvent::new;\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/support/TestWaiter.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.RingBuffer;\nimport com.lmax.disruptor.SequenceBarrier;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CyclicBarrier;\n\npublic final class TestWaiter implements Callable<List<StubEvent>>\n{\n    private final long toWaitForSequence;\n    private final long initialSequence;\n    private final CyclicBarrier cyclicBarrier;\n    private final SequenceBarrier sequenceBarrier;\n    private final RingBuffer<StubEvent> ringBuffer;\n\n    public TestWaiter(\n        final CyclicBarrier cyclicBarrier,\n        final SequenceBarrier sequenceBarrier,\n        final RingBuffer<StubEvent> ringBuffer,\n        final long initialSequence,\n        final long toWaitForSequence)\n    {\n        this.cyclicBarrier = cyclicBarrier;\n        this.initialSequence = initialSequence;\n        this.ringBuffer = ringBuffer;\n        this.toWaitForSequence = toWaitForSequence;\n        this.sequenceBarrier = sequenceBarrier;\n    }\n\n    @Override\n    public List<StubEvent> call() throws Exception\n    {\n        cyclicBarrier.await();\n        sequenceBarrier.waitFor(toWaitForSequence);\n\n        final List<StubEvent> messages = new ArrayList<>();\n        for (long l = initialSequence; l <= toWaitForSequence; l++)\n        {\n            messages.add(ringBuffer.get(l));\n        }\n\n        return messages;\n    }\n}"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/support/WaitStrategyTestUtil.java",
    "content": "/*\n * Copyright 2012 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.support;\n\nimport com.lmax.disruptor.AlertException;\nimport com.lmax.disruptor.Sequence;\nimport com.lmax.disruptor.TimeoutException;\nimport com.lmax.disruptor.WaitStrategy;\n\nimport java.util.concurrent.BrokenBarrierException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\npublic class WaitStrategyTestUtil\n{\n    private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool();\n\n    public static void assertWaitForWithDelayOf(final long sleepTimeMillis, final WaitStrategy waitStrategy)\n        throws InterruptedException, BrokenBarrierException, AlertException, TimeoutException\n    {\n        SequenceUpdater sequenceUpdater = new SequenceUpdater(sleepTimeMillis, waitStrategy);\n        EXECUTOR.execute(sequenceUpdater);\n        sequenceUpdater.waitForStartup();\n        Sequence cursor = new Sequence(0);\n        long sequence = waitStrategy.waitFor(0, cursor, sequenceUpdater.sequence, new DummySequenceBarrier());\n\n        assertThat(sequence, is(0L));\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/util/MutableLong.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.util;\n\n/**\n * Holder class for a long value.\n */\npublic class MutableLong\n{\n    private long value = 0L;\n\n    /**\n     * Default constructor\n     */\n    public MutableLong()\n    {\n    }\n\n    /**\n     * Construct the holder with initial value.\n     *\n     * @param initialValue to be initially set.\n     */\n    public MutableLong(final long initialValue)\n    {\n        this.value = initialValue;\n    }\n\n    /**\n     * Get the long value.\n     *\n     * @return the long value.\n     */\n    public long get()\n    {\n        return value;\n    }\n\n    /**\n     * Set the long value.\n     *\n     * @param value to set.\n     */\n    public void set(final long value)\n    {\n        this.value = value;\n    }\n\n    /**\n     * Increments the value\n     */\n    public void increment()\n    {\n        value++;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/util/PaddedLong.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.util;\n\n/**\n * Cache line padded long variable to be used when false sharing maybe an issue.\n */\npublic final class PaddedLong extends MutableLong\n{\n    public volatile long p1, p2, p3, p4, p5, p6 = 7L;\n\n    /**\n     * Default constructor\n     */\n    public PaddedLong()\n    {\n    }\n\n    /**\n     * Construct with an initial value.\n     *\n     * @param initialValue for construction\n     */\n    public PaddedLong(final long initialValue)\n    {\n        super(initialValue);\n    }\n\n    public long sumPaddingToPreventOptimisation()\n    {\n        return p1 + p2 + p3 + p4 + p5 + p6;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/util/UnsafeAccess.java",
    "content": "package com.lmax.disruptor.util;\n\nimport java.lang.reflect.Field;\nimport java.security.AccessController;\nimport java.security.PrivilegedExceptionAction;\n\npublic class UnsafeAccess\n{\n    private static final sun.misc.Unsafe THE_UNSAFE;\n\n    static\n    {\n        try\n        {\n            final PrivilegedExceptionAction<sun.misc.Unsafe> action = () ->\n            {\n                Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField(\"theUnsafe\");\n                theUnsafe.setAccessible(true);\n                return (sun.misc.Unsafe) theUnsafe.get(null);\n            };\n\n            THE_UNSAFE = AccessController.doPrivileged(action);\n        }\n        catch (Exception e)\n        {\n            throw new RuntimeException(\"Unable to load unsafe\", e);\n        }\n    }\n\n    /**\n     * Get a handle on the Unsafe instance, used for accessing low-level concurrency\n     * and memory constructs.\n     *\n     * @return The Unsafe\n     */\n    public static sun.misc.Unsafe getUnsafe()\n    {\n        return THE_UNSAFE;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/lmax/disruptor/util/UtilTest.java",
    "content": "/*\n * Copyright 2011 LMAX Ltd.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lmax.disruptor.util;\n\nimport com.lmax.disruptor.Sequence;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\npublic final class UtilTest\n{\n    @Test\n    public void shouldReturnNextPowerOfTwo()\n    {\n        int powerOfTwo = Util.ceilingNextPowerOfTwo(1000);\n\n        assertEquals(1024, powerOfTwo);\n    }\n\n    @Test\n    public void shouldReturnExactPowerOfTwo()\n    {\n        int powerOfTwo = Util.ceilingNextPowerOfTwo(1024);\n\n        assertEquals(1024, powerOfTwo);\n    }\n\n    @Test\n    public void shouldReturnMinimumSequence()\n    {\n        final Sequence[] sequences = {new Sequence(7L), new Sequence(3L), new Sequence(12L)};\n        assertEquals(3L, Util.getMinimumSequence(sequences));\n    }\n\n    @Test\n    public void shouldReturnLongMaxWhenNoEventProcessors()\n    {\n        final Sequence[] sequences = new Sequence[0];\n\n        assertEquals(Long.MAX_VALUE, Util.getMinimumSequence(sequences));\n    }\n\n    @Test\n    void shouldThrowErrorIfValuePassedToLog2FunctionIsNotPositive()\n    {\n        assertThrows(IllegalArgumentException.class, () -> Util.log2(0));\n        assertThrows(IllegalArgumentException.class, () -> Util.log2(-1));\n        assertThrows(IllegalArgumentException.class, () -> Util.log2(Integer.MIN_VALUE));\n    }\n\n    @Test\n    void shouldCalculateCorrectlyIntegerFlooredLog2()\n    {\n        assertEquals(0, Util.log2(1));\n        assertEquals(1, Util.log2(2));\n        assertEquals(1, Util.log2(3));\n        assertEquals(10, Util.log2(1024));\n        assertEquals(30, Util.log2(Integer.MAX_VALUE));\n    }\n}\n"
  }
]