neo4j-ruby-driver 1.7.5 → 4.4.0.alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +26 -42
- data/lib/loader.rb +5 -3
- data/lib/neo4j/driver/auto_closable.rb +2 -2
- data/lib/neo4j/driver/exceptions/authentication_exception.rb +6 -1
- data/lib/neo4j/driver/exceptions/authorization_expired_exception.rb +14 -0
- data/lib/neo4j/driver/{types/bytes.rb → exceptions/certificate_exception.rb} +2 -2
- data/lib/neo4j/driver/exceptions/client_exception.rb +3 -0
- data/lib/neo4j/driver/exceptions/connection_read_timeout_exception.rb +14 -0
- data/lib/neo4j/driver/exceptions/database_exception.rb +3 -0
- data/lib/neo4j/driver/exceptions/discovery_exception.rb +16 -0
- data/lib/neo4j/driver/exceptions/fatal_discovery_exception.rb +13 -0
- data/lib/neo4j/driver/exceptions/protocol_exception.rb +7 -0
- data/lib/neo4j/driver/exceptions/result_consumed_exception.rb +13 -0
- data/lib/neo4j/driver/exceptions/security_exception.rb +5 -1
- data/lib/neo4j/driver/exceptions/service_unavailable_exception.rb +2 -0
- data/lib/neo4j/driver/exceptions/session_expired_exception.rb +4 -0
- data/lib/neo4j/driver/exceptions/token_expired_exception.rb +15 -0
- data/lib/neo4j/driver/exceptions/transaction_nesting_exception.rb +11 -0
- data/lib/neo4j/driver/exceptions/transient_exception.rb +3 -0
- data/lib/neo4j/driver/exceptions/untrusted_server_exception.rb +1 -0
- data/lib/neo4j/driver/exceptions/value/lossy_coercion.rb +15 -0
- data/lib/neo4j/driver/exceptions/value/not_multi_valued.rb +13 -0
- data/lib/neo4j/driver/exceptions/value/uncoercible.rb +15 -0
- data/lib/neo4j/driver/exceptions/value/unsizable.rb +12 -0
- data/lib/neo4j/driver/exceptions/value/value_exception.rb +12 -0
- data/lib/neo4j/driver/internal/bolt_server_address.rb +97 -0
- data/lib/neo4j/driver/internal/duration_normalizer.rb +1 -1
- data/lib/neo4j/driver/internal/validator.rb +5 -4
- data/{ffi/neo4j/driver/summary/statement_type.rb → lib/neo4j/driver/summary/query_type.rb} +1 -3
- data/lib/neo4j/driver/synchronizable.rb +23 -0
- data/lib/neo4j_ruby_driver.rb +5 -10
- data/{ffi → ruby}/neo4j/driver/access_mode.rb +2 -2
- data/ruby/neo4j/driver/auth_tokens.rb +34 -0
- data/ruby/neo4j/driver/bookmark.rb +21 -0
- data/ruby/neo4j/driver/config.rb +91 -0
- data/ruby/neo4j/driver/graph_database.rb +140 -0
- data/ruby/neo4j/driver/internal/async/connection/bolt_protocol_util.rb +51 -0
- data/ruby/neo4j/driver/internal/async/connection/bootstrap_factory.rb +22 -0
- data/ruby/neo4j/driver/internal/async/connection/channel_attributes.rb +31 -0
- data/ruby/neo4j/driver/internal/async/connection/channel_connected_listener.rb +32 -0
- data/ruby/neo4j/driver/internal/async/connection/channel_connector_impl.rb +77 -0
- data/ruby/neo4j/driver/internal/async/connection/channel_pipeline_builder_impl.rb +22 -0
- data/ruby/neo4j/driver/internal/async/connection/direct_connection.rb +30 -0
- data/ruby/neo4j/driver/internal/async/connection/event_loop_group_factory.rb +83 -0
- data/ruby/neo4j/driver/internal/async/connection/handshake_completed_listener.rb +27 -0
- data/ruby/neo4j/driver/internal/async/connection/handshake_handler.rb +113 -0
- data/ruby/neo4j/driver/internal/async/connection/netty_channel_initializer.rb +57 -0
- data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver.rb +26 -0
- data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver_group.rb +19 -0
- data/ruby/neo4j/driver/internal/async/connection/routing_connection.rb +36 -0
- data/ruby/neo4j/driver/internal/async/connection/stream.rb +12 -0
- data/ruby/neo4j/driver/internal/async/connection/stream_reader.rb +16 -0
- data/ruby/neo4j/driver/internal/async/connection_context.rb +10 -0
- data/ruby/neo4j/driver/internal/async/immutable_connection_context.rb +24 -0
- data/ruby/neo4j/driver/internal/async/inbound/byte_buf_input.rb +30 -0
- data/ruby/neo4j/driver/internal/async/inbound/channel_error_handler.rb +77 -0
- data/ruby/neo4j/driver/internal/async/inbound/chunk_decoder.rb +41 -0
- data/ruby/neo4j/driver/internal/async/inbound/connect_timeout_handler.rb +32 -0
- data/ruby/neo4j/driver/internal/async/inbound/connection_read_timeout_handler.rb +17 -0
- data/ruby/neo4j/driver/internal/async/inbound/inbound_message_dispatcher.rb +172 -0
- data/ruby/neo4j/driver/internal/async/inbound/inbound_message_handler.rb +42 -0
- data/ruby/neo4j/driver/internal/async/inbound/message_decoder.rb +51 -0
- data/ruby/neo4j/driver/internal/async/internal_async_session.rb +98 -0
- data/ruby/neo4j/driver/internal/async/internal_async_transaction.rb +13 -0
- data/ruby/neo4j/driver/internal/async/leak_logging_network_session.rb +34 -0
- data/ruby/neo4j/driver/internal/async/network_connection.rb +196 -0
- data/ruby/neo4j/driver/internal/async/network_session.rb +152 -0
- data/ruby/neo4j/driver/internal/async/outbound/chunk_aware_byte_buf_output.rb +110 -0
- data/ruby/neo4j/driver/internal/async/outbound/outbound_message_handler.rb +39 -0
- data/ruby/neo4j/driver/internal/async/pool/channel.rb +63 -0
- data/ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb +149 -0
- data/ruby/neo4j/driver/internal/async/pool/controller.rb +25 -0
- data/ruby/neo4j/driver/internal/async/pool/netty_channel_health_checker.rb +87 -0
- data/ruby/neo4j/driver/internal/async/pool/netty_channel_pool.rb +52 -0
- data/ruby/neo4j/driver/internal/async/pool/netty_channel_tracker.rb +137 -0
- data/ruby/neo4j/driver/internal/async/pool/network_connection_factory.rb +21 -0
- data/ruby/neo4j/driver/internal/async/pool/pool_settings.rb +34 -0
- data/ruby/neo4j/driver/internal/async/result_cursors_holder.rb +17 -0
- data/ruby/neo4j/driver/internal/async/unmanaged_transaction.rb +214 -0
- data/ruby/neo4j/driver/internal/bookmark_holder.rb +9 -0
- data/ruby/neo4j/driver/internal/cluster/cluster_composition.rb +58 -0
- data/ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb +14 -0
- data/ruby/neo4j/driver/internal/cluster/cluster_routing_table.rb +139 -0
- data/ruby/neo4j/driver/internal/cluster/identity_resolver.rb +13 -0
- data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb +68 -0
- data/ruby/neo4j/driver/internal/cluster/loadbalancing/load_balancer.rb +159 -0
- data/ruby/neo4j/driver/internal/cluster/loadbalancing/round_robin_array_index.rb +13 -0
- data/ruby/neo4j/driver/internal/cluster/multi_databases_routing_procedure_runner.rb +34 -0
- data/ruby/neo4j/driver/internal/cluster/rediscovery_impl.rb +238 -0
- data/ruby/neo4j/driver/internal/cluster/route_message_routing_procedure_runner.rb +43 -0
- data/ruby/neo4j/driver/internal/cluster/routing_context.rb +77 -0
- data/ruby/neo4j/driver/internal/cluster/routing_procedure_cluster_composition_provider.rb +64 -0
- data/ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb +19 -0
- data/ruby/neo4j/driver/internal/cluster/routing_settings.rb +24 -0
- data/ruby/neo4j/driver/internal/cluster/routing_table_handler_impl.rb +116 -0
- data/ruby/neo4j/driver/internal/cluster/routing_table_registry_impl.rb +140 -0
- data/ruby/neo4j/driver/internal/cluster/single_database_routing_procedure_runner.rb +76 -0
- data/ruby/neo4j/driver/internal/connection_settings.rb +16 -0
- data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +76 -0
- data/ruby/neo4j/driver/internal/cursor/async_result_cursor_only_factory.rb +29 -0
- data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +59 -0
- data/ruby/neo4j/driver/internal/cursor/result_cursor_factory_impl.rb +29 -0
- data/ruby/neo4j/driver/internal/cursor/rx_result_cursor_impl.rb +110 -0
- data/ruby/neo4j/driver/internal/database_name.rb +12 -0
- data/ruby/neo4j/driver/internal/database_name_util.rb +37 -0
- data/ruby/neo4j/driver/internal/default_bookmark_holder.rb +15 -0
- data/ruby/neo4j/driver/internal/default_domain_name_resolver.rb +11 -0
- data/ruby/neo4j/driver/internal/direct_connection_provider.rb +40 -0
- data/ruby/neo4j/driver/internal/driver_factory.rb +127 -0
- data/ruby/neo4j/driver/internal/handlers/begin_tx_response_handler.rb +20 -0
- data/ruby/neo4j/driver/internal/handlers/channel_releasing_reset_response_handler.rb +29 -0
- data/ruby/neo4j/driver/internal/handlers/commit_tx_response_handler.rb +25 -0
- data/ruby/neo4j/driver/internal/handlers/hello_response_handler.rb +65 -0
- data/ruby/neo4j/driver/internal/handlers/init_response_handler.rb +34 -0
- data/ruby/neo4j/driver/internal/handlers/legacy_pull_all_response_handler.rb +228 -0
- data/ruby/neo4j/driver/internal/handlers/no_op_response_handler.rb +16 -0
- data/ruby/neo4j/driver/internal/handlers/ping_response_handler.rb +29 -0
- data/ruby/neo4j/driver/internal/handlers/pull_handlers.rb +32 -0
- data/ruby/neo4j/driver/internal/handlers/pulln/auto_pull_response_handler.rb +174 -0
- data/ruby/neo4j/driver/internal/handlers/pulln/basic_pull_response_handler.rb +288 -0
- data/ruby/neo4j/driver/internal/handlers/pulln/fetch_size_util.rb +20 -0
- data/ruby/neo4j/driver/internal/handlers/reset_response_handler.rb +34 -0
- data/ruby/neo4j/driver/internal/handlers/rollback_tx_response_handler.rb +19 -0
- data/ruby/neo4j/driver/internal/handlers/route_message_response_handler.rb +21 -0
- data/ruby/neo4j/driver/internal/handlers/routing_response_handler.rb +70 -0
- data/ruby/neo4j/driver/internal/handlers/run_response_handler.rb +37 -0
- data/ruby/neo4j/driver/internal/handlers/session_pull_response_completion_listener.rb +34 -0
- data/ruby/neo4j/driver/internal/handlers/transaction_pull_response_completion_listener.rb +20 -0
- data/ruby/neo4j/driver/internal/impersonation_util.rb +22 -0
- data/ruby/neo4j/driver/internal/internal_bookmark.rb +38 -0
- data/ruby/neo4j/driver/internal/internal_database_name.rb +11 -0
- data/ruby/neo4j/driver/internal/internal_driver.rb +78 -0
- data/ruby/neo4j/driver/internal/internal_entity.rb +22 -0
- data/ruby/neo4j/driver/internal/internal_node.rb +21 -0
- data/ruby/neo4j/driver/internal/internal_pair.rb +9 -0
- data/ruby/neo4j/driver/internal/internal_path.rb +35 -0
- data/ruby/neo4j/driver/internal/internal_point2_d.rb +9 -0
- data/ruby/neo4j/driver/internal/internal_point3_d.rb +6 -0
- data/{ffi → ruby}/neo4j/driver/internal/internal_record.rb +2 -1
- data/ruby/neo4j/driver/internal/internal_relationship.rb +26 -0
- data/ruby/neo4j/driver/internal/internal_result.rb +60 -0
- data/ruby/neo4j/driver/internal/internal_session.rb +81 -0
- data/ruby/neo4j/driver/internal/internal_transaction.rb +48 -0
- data/ruby/neo4j/driver/internal/logging/channel_activity_logger.rb +29 -0
- data/ruby/neo4j/driver/internal/logging/channel_error_logger.rb +17 -0
- data/ruby/neo4j/driver/internal/logging/prefixed_logger.rb +19 -0
- data/ruby/neo4j/driver/internal/logging/reformatted_logger.rb +17 -0
- data/ruby/neo4j/driver/internal/messaging/abstract_message_writer.rb +23 -0
- data/ruby/neo4j/driver/internal/messaging/bolt_protocol.rb +30 -0
- data/ruby/neo4j/driver/internal/messaging/bolt_protocol_version.rb +46 -0
- data/ruby/neo4j/driver/internal/messaging/common/common_message_reader.rb +51 -0
- data/ruby/neo4j/driver/internal/messaging/common/common_value.rb +31 -0
- data/ruby/neo4j/driver/internal/messaging/common/common_value_packer.rb +101 -0
- data/ruby/neo4j/driver/internal/messaging/common/common_value_unpacker.rb +234 -0
- data/ruby/neo4j/driver/internal/messaging/encode/begin_message_encoder.rb +15 -0
- data/ruby/neo4j/driver/internal/messaging/encode/commit_message_encoder.rb +14 -0
- data/ruby/neo4j/driver/internal/messaging/encode/discard_all_message_encoder.rb +14 -0
- data/ruby/neo4j/driver/internal/messaging/encode/discard_message_encoder.rb +15 -0
- data/ruby/neo4j/driver/internal/messaging/encode/goodbye_message_encoder.rb +14 -0
- data/ruby/neo4j/driver/internal/messaging/encode/hello_message_encoder.rb +15 -0
- data/ruby/neo4j/driver/internal/messaging/encode/init_message_encoder.rb +16 -0
- data/ruby/neo4j/driver/internal/messaging/encode/pull_all_message_encoder.rb +14 -0
- data/ruby/neo4j/driver/internal/messaging/encode/pull_message_encoder.rb +15 -0
- data/ruby/neo4j/driver/internal/messaging/encode/reset_message_encoder.rb +14 -0
- data/ruby/neo4j/driver/internal/messaging/encode/rollback_message_encoder.rb +14 -0
- data/ruby/neo4j/driver/internal/messaging/encode/route_message_encoder.rb +18 -0
- data/ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb +27 -0
- data/ruby/neo4j/driver/internal/messaging/encode/run_message_encoder.rb +16 -0
- data/ruby/neo4j/driver/internal/messaging/encode/run_with_metadata_message_encoder.rb +17 -0
- data/ruby/neo4j/driver/internal/messaging/request/abstract_streaming_message.rb +22 -0
- data/ruby/neo4j/driver/internal/messaging/request/begin_message.rb +26 -0
- data/ruby/neo4j/driver/internal/messaging/request/commit_message.rb +20 -0
- data/ruby/neo4j/driver/internal/messaging/request/discard_all_message.rb +20 -0
- data/ruby/neo4j/driver/internal/messaging/request/discard_message.rb +23 -0
- data/ruby/neo4j/driver/internal/messaging/request/goodbye_message.rb +20 -0
- data/ruby/neo4j/driver/internal/messaging/request/hello_message.rb +31 -0
- data/ruby/neo4j/driver/internal/messaging/request/init_message.rb +19 -0
- data/ruby/neo4j/driver/internal/messaging/request/message_with_metadata.rb +10 -0
- data/ruby/neo4j/driver/internal/messaging/request/multi_database_util.rb +26 -0
- data/ruby/neo4j/driver/internal/messaging/request/pull_all_message.rb +23 -0
- data/ruby/neo4j/driver/internal/messaging/request/pull_message.rb +22 -0
- data/ruby/neo4j/driver/internal/messaging/request/reset_message.rb +32 -0
- data/ruby/neo4j/driver/internal/messaging/request/rollback_message.rb +20 -0
- data/ruby/neo4j/driver/internal/messaging/request/route_message.rb +33 -0
- data/ruby/neo4j/driver/internal/messaging/request/run_message.rb +23 -0
- data/ruby/neo4j/driver/internal/messaging/request/run_with_metadata_message.rb +47 -0
- data/ruby/neo4j/driver/internal/messaging/request/transaction_metadata_builder.rb +24 -0
- data/ruby/neo4j/driver/internal/messaging/response/failure_message.rb +40 -0
- data/ruby/neo4j/driver/internal/messaging/response/ignored_message.rb +29 -0
- data/ruby/neo4j/driver/internal/messaging/response/record_message.rb +33 -0
- data/ruby/neo4j/driver/internal/messaging/response/success_message.rb +34 -0
- data/ruby/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +79 -0
- data/ruby/neo4j/driver/internal/messaging/v3/message_format_v3.rb +17 -0
- data/ruby/neo4j/driver/internal/messaging/v3/message_writer_v3.rb +27 -0
- data/ruby/neo4j/driver/internal/messaging/v4/bolt_protocol_v4.rb +29 -0
- data/ruby/neo4j/driver/internal/messaging/v4/message_format_v4.rb +17 -0
- data/ruby/neo4j/driver/internal/messaging/v4/message_writer_v4.rb +28 -0
- data/ruby/neo4j/driver/internal/messaging/v41/bolt_protocol_v41.rb +25 -0
- data/ruby/neo4j/driver/internal/messaging/v42/bolt_protocol_v42.rb +13 -0
- data/ruby/neo4j/driver/internal/messaging/v43/bolt_protocol_v43.rb +19 -0
- data/ruby/neo4j/driver/internal/messaging/v43/message_format_v43.rb +18 -0
- data/ruby/neo4j/driver/internal/messaging/v43/message_writer_v43.rb +34 -0
- data/ruby/neo4j/driver/internal/messaging/v44/bolt_protocol_v44.rb +17 -0
- data/ruby/neo4j/driver/internal/messaging/v44/message_format_v44.rb +18 -0
- data/ruby/neo4j/driver/internal/messaging/v44/message_writer_v44.rb +26 -0
- data/ruby/neo4j/driver/internal/metrics/connection_pool_metrics_listener.rb +34 -0
- data/ruby/neo4j/driver/internal/metrics/internal_abstract_metrics.rb +46 -0
- data/ruby/neo4j/driver/internal/metrics/internal_connection_pool_metrics.rb +105 -0
- data/ruby/neo4j/driver/internal/metrics/internal_metrics.rb +82 -0
- data/ruby/neo4j/driver/internal/metrics/internal_metrics_provider.rb +18 -0
- data/ruby/neo4j/driver/internal/metrics/listener_event.rb +17 -0
- data/ruby/neo4j/driver/internal/metrics/metrics_provider.rb +24 -0
- data/ruby/neo4j/driver/internal/metrics/time_recorder_listener_event.rb +15 -0
- data/ruby/neo4j/driver/internal/packstream/byte_array_incompatible_packer.rb +12 -0
- data/ruby/neo4j/driver/internal/packstream/pack_input.rb +47 -0
- data/ruby/neo4j/driver/internal/packstream/pack_output.rb +39 -0
- data/ruby/neo4j/driver/internal/packstream/pack_stream.rb +326 -0
- data/ruby/neo4j/driver/internal/packstream/pack_type.rb +17 -0
- data/ruby/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb +151 -0
- data/ruby/neo4j/driver/internal/revocation_strategy.rb +19 -0
- data/ruby/neo4j/driver/internal/scheme.rb +32 -0
- data/ruby/neo4j/driver/internal/security/internal_auth_token.rb +15 -0
- data/ruby/neo4j/driver/internal/security/security_plan_impl.rb +92 -0
- data/ruby/neo4j/driver/internal/security_setting.rb +73 -0
- data/ruby/neo4j/driver/internal/session_factory_impl.rb +32 -0
- data/ruby/neo4j/driver/internal/spi/connection.rb +19 -0
- data/ruby/neo4j/driver/internal/spi/connection_pool.rb +9 -0
- data/ruby/neo4j/driver/internal/spi/response_handler.rb +23 -0
- data/ruby/neo4j/driver/internal/summary/internal_database_info.rb +7 -0
- data/ruby/neo4j/driver/internal/summary/internal_input_position.rb +11 -0
- data/ruby/neo4j/driver/internal/summary/internal_notification.rb +16 -0
- data/ruby/neo4j/driver/internal/summary/internal_plan.rb +41 -0
- data/ruby/neo4j/driver/internal/summary/internal_profiled_plan.rb +32 -0
- data/ruby/neo4j/driver/internal/summary/internal_result_summary.rb +33 -0
- data/ruby/neo4j/driver/internal/summary/internal_server_info.rb +6 -0
- data/ruby/neo4j/driver/internal/summary/internal_summary_counters.rb +18 -0
- data/ruby/neo4j/driver/internal/svm/netty_substitutions.rb +196 -0
- data/ruby/neo4j/driver/internal/svm/z_lib_substitutions.rb +21 -0
- data/ruby/neo4j/driver/internal/util/certificate_tool.rb +65 -0
- data/ruby/neo4j/driver/internal/util/clock.rb +29 -0
- data/ruby/neo4j/driver/internal/util/error_util.rb +104 -0
- data/ruby/neo4j/driver/internal/util/extract.rb +123 -0
- data/ruby/neo4j/driver/internal/util/format.rb +39 -0
- data/ruby/neo4j/driver/internal/util/futures.rb +99 -0
- data/ruby/neo4j/driver/internal/util/iterables.rb +35 -0
- data/ruby/neo4j/driver/internal/util/lock_util.rb +23 -0
- data/ruby/neo4j/driver/internal/util/metadata_extractor.rb +109 -0
- data/ruby/neo4j/driver/internal/util/mutex.rb +9 -0
- data/ruby/neo4j/driver/internal/util/preconditions.rb +16 -0
- data/ruby/neo4j/driver/internal/util/server_version.rb +60 -0
- data/ruby/neo4j/driver/logging1.rb +51 -0
- data/ruby/neo4j/driver/net/server_address1.rb +9 -0
- data/ruby/neo4j/driver/query.rb +48 -0
- data/ruby/neo4j/driver/records.rb +13 -0
- data/ruby/neo4j/driver/session_config.rb +15 -0
- data/ruby/neo4j/driver/transaction_config.rb +46 -0
- data/ruby/neo4j/driver/values.rb +26 -0
- data/{lib → ruby}/neo4j/driver/version.rb +1 -1
- data/ruby/neo4j/driver.rb +30 -0
- metadata +267 -92
- data/ffi/bolt/address.rb +0 -11
- data/ffi/bolt/address_resolver.rb +0 -12
- data/ffi/bolt/address_set.rb +0 -9
- data/ffi/bolt/auth.rb +0 -10
- data/ffi/bolt/auto_releasable.rb +0 -22
- data/ffi/bolt/boolean.rb +0 -9
- data/ffi/bolt/bytes.rb +0 -10
- data/ffi/bolt/config.rb +0 -45
- data/ffi/bolt/connection.rb +0 -44
- data/ffi/bolt/connector.rb +0 -17
- data/ffi/bolt/dictionary.rb +0 -15
- data/ffi/bolt/error.rb +0 -74
- data/ffi/bolt/float.rb +0 -9
- data/ffi/bolt/integer.rb +0 -9
- data/ffi/bolt/library.rb +0 -12
- data/ffi/bolt/lifecycle.rb +0 -9
- data/ffi/bolt/list.rb +0 -10
- data/ffi/bolt/log.rb +0 -16
- data/ffi/bolt/socket_options.rb +0 -14
- data/ffi/bolt/status.rb +0 -25
- data/ffi/bolt/string.rb +0 -9
- data/ffi/bolt/structure.rb +0 -10
- data/ffi/bolt/value.rb +0 -35
- data/ffi/neo4j/driver/auth_tokens.rb +0 -18
- data/ffi/neo4j/driver/config.rb +0 -40
- data/ffi/neo4j/driver/graph_database.rb +0 -52
- data/ffi/neo4j/driver/internal/async/access_mode_connection.rb +0 -19
- data/ffi/neo4j/driver/internal/async/direct_connection.rb +0 -106
- data/ffi/neo4j/driver/internal/bolt_server_address.rb +0 -18
- data/ffi/neo4j/driver/internal/bookmarks_holder.rb +0 -30
- data/ffi/neo4j/driver/internal/direct_connection_provider.rb +0 -28
- data/ffi/neo4j/driver/internal/driver_factory.rb +0 -126
- data/ffi/neo4j/driver/internal/error_handling.rb +0 -112
- data/ffi/neo4j/driver/internal/explicit_transaction.rb +0 -146
- data/ffi/neo4j/driver/internal/handlers/pull_all_response_handler.rb +0 -104
- data/ffi/neo4j/driver/internal/handlers/response_handler.rb +0 -49
- data/ffi/neo4j/driver/internal/handlers/run_response_handler.rb +0 -32
- data/ffi/neo4j/driver/internal/handlers/session_pull_all_response_handler.rb +0 -32
- data/ffi/neo4j/driver/internal/handlers/transaction_pull_all_response_handler.rb +0 -23
- data/ffi/neo4j/driver/internal/internal_driver.rb +0 -45
- data/ffi/neo4j/driver/internal/internal_logger.rb +0 -32
- data/ffi/neo4j/driver/internal/internal_resolver.rb +0 -31
- data/ffi/neo4j/driver/internal/internal_statement_result.rb +0 -52
- data/ffi/neo4j/driver/internal/messaging/bolt_protocol.rb +0 -24
- data/ffi/neo4j/driver/internal/messaging/v1/bolt_protocol_v1.rb +0 -59
- data/ffi/neo4j/driver/internal/messaging/v2/bolt_protocol_v2.rb +0 -16
- data/ffi/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +0 -63
- data/ffi/neo4j/driver/internal/network_session.rb +0 -129
- data/ffi/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb +0 -80
- data/ffi/neo4j/driver/internal/session_factory_impl.rb +0 -28
- data/ffi/neo4j/driver/internal/summary/internal_result_summary.rb +0 -67
- data/ffi/neo4j/driver/internal/summary/internal_server_info.rb +0 -19
- data/ffi/neo4j/driver/internal/summary/internal_summary_counters.rb +0 -23
- data/ffi/neo4j/driver/internal/util/metadata_extractor.rb +0 -15
- data/ffi/neo4j/driver/internal/value/base_time_value.rb +0 -22
- data/ffi/neo4j/driver/internal/value/date_value.rb +0 -25
- data/ffi/neo4j/driver/internal/value/duration_value.rb +0 -27
- data/ffi/neo4j/driver/internal/value/local_date_time_value.rb +0 -24
- data/ffi/neo4j/driver/internal/value/local_time_value.rb +0 -19
- data/ffi/neo4j/driver/internal/value/node_value.rb +0 -18
- data/ffi/neo4j/driver/internal/value/offset_time_value.rb +0 -25
- data/ffi/neo4j/driver/internal/value/path_value.rb +0 -41
- data/ffi/neo4j/driver/internal/value/point2_d_value.rb +0 -24
- data/ffi/neo4j/driver/internal/value/point3_d_value.rb +0 -24
- data/ffi/neo4j/driver/internal/value/relationship_value.rb +0 -18
- data/ffi/neo4j/driver/internal/value/structure_value.rb +0 -42
- data/ffi/neo4j/driver/internal/value/time_with_zone_id_value.rb +0 -25
- data/ffi/neo4j/driver/internal/value/time_with_zone_offset_value.rb +0 -28
- data/ffi/neo4j/driver/internal/value/unbound_relationship_value.rb +0 -18
- data/ffi/neo4j/driver/internal/value/value_adapter.rb +0 -101
- data/ffi/neo4j/driver/net/server_address.rb +0 -13
- data/ffi/neo4j/driver/statement.rb +0 -15
- data/ffi/neo4j/driver/types/entity.rb +0 -21
- data/ffi/neo4j/driver/types/node.rb +0 -16
- data/ffi/neo4j/driver/types/path.rb +0 -35
- data/ffi/neo4j/driver/types/relationship.rb +0 -19
- data/ffi/neo4j/driver.rb +0 -61
- data/lib/neo4j/driver/internal/ruby_signature.rb +0 -18
data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Neo4j::Driver
|
|
2
|
+
module Internal
|
|
3
|
+
module Cluster
|
|
4
|
+
module Loadbalancing
|
|
5
|
+
|
|
6
|
+
# Load balancing strategy that finds server with the least amount of active (checked out of the pool) connections from given readers or writers. It finds a
|
|
7
|
+
# start index for iteration in a round-robin fashion. This is done to prevent choosing same first address over and over when all addresses have the same amount
|
|
8
|
+
# of active connections.
|
|
9
|
+
class LeastConnectedLoadBalancingStrategy
|
|
10
|
+
|
|
11
|
+
def initialize(connection_pool, logger)
|
|
12
|
+
@readers_index = RoundRobinArrayIndex.new
|
|
13
|
+
@writers_index = RoundRobinArrayIndex.new
|
|
14
|
+
|
|
15
|
+
@connection_pool = connection_pool
|
|
16
|
+
@log = logger
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def select_reader(known_readers)
|
|
20
|
+
select(known_readers, @readers_index, 'reader')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def select_writer(known_writers)
|
|
24
|
+
select(known_writers, @writers_index, 'writer')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def select(addresses, addresses_index, address_type)
|
|
30
|
+
size = addresses.size
|
|
31
|
+
|
|
32
|
+
if size == 0
|
|
33
|
+
@log.debug("Unable to select #{address_type}, no known addresses given")
|
|
34
|
+
return nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# choose start index for iteration in round-robin fashion
|
|
38
|
+
start_index = addresses_index.next(size)
|
|
39
|
+
index = start_index
|
|
40
|
+
|
|
41
|
+
least_connected_address = nil
|
|
42
|
+
least_active_connections = java.lang.Integer::MAX_VALUE
|
|
43
|
+
|
|
44
|
+
# iterate over the array to find the least connected address
|
|
45
|
+
loop do
|
|
46
|
+
address = addresses[index]
|
|
47
|
+
active_connections = @connection_pool.in_use_connections(address)
|
|
48
|
+
|
|
49
|
+
if active_connections < least_active_connections
|
|
50
|
+
least_connected_address = address
|
|
51
|
+
least_active_connections = active_connections
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# loop over to the start of the array when end is reached
|
|
55
|
+
index = (index == size - 1) ? 0 : index += 1
|
|
56
|
+
|
|
57
|
+
break if index != start_index
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
@log.debug("Selected #{address_type} with address: '#{least_connected_address}' and active connections: #{least_active_connections}")
|
|
61
|
+
|
|
62
|
+
least_connected_address
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
module Neo4j::Driver
|
|
2
|
+
module Internal
|
|
3
|
+
module Cluster
|
|
4
|
+
module Loadbalancing
|
|
5
|
+
class LoadBalancer
|
|
6
|
+
CONNECTION_ACQUISITION_COMPLETION_FAILURE_MESSAGE = 'Connection acquisition failed for all available addresses.'
|
|
7
|
+
CONNECTION_ACQUISITION_COMPLETION_EXCEPTION_MESSAGE = "Failed to obtain connection towards %s server. Known routing table is: %s"
|
|
8
|
+
CONNECTION_ACQUISITION_ATTEMPT_FAILURE_MESSAGE = "Failed to obtain a connection towards address %s, will try other addresses if available. Complete failure is reported separately from this entry."
|
|
9
|
+
BOLT_SERVER_ADDRESSES_EMPTY_ARRAY = []
|
|
10
|
+
|
|
11
|
+
attr_reader :routing_tables
|
|
12
|
+
|
|
13
|
+
delegate :close, to: :@connection_pool
|
|
14
|
+
|
|
15
|
+
def initialize(initial_router, settings, connection_pool, event_executor_group, logger, load_balancing_strategy, resolver, &domain_name_resolver)
|
|
16
|
+
clock = Util::Clock::System
|
|
17
|
+
@connection_pool = connection_pool
|
|
18
|
+
@rediscovery = create_rediscovery(event_executor_group, initial_router, resolver, settings, clock, logger, domain_name_resolver)
|
|
19
|
+
@routing_tables = create_routing_tables(connection_pool, @rediscovery, settings, clock, logger)
|
|
20
|
+
@load_balancing_strategy = load_balancing_strategy
|
|
21
|
+
@event_executor_group = event_executor_group
|
|
22
|
+
@log = logger
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def acquire_connection(context)
|
|
26
|
+
@routing_tables.ensure_routing_table(context).then_flat do |handler|
|
|
27
|
+
acquire(context.mode, handler.routing_table).then do |connection|
|
|
28
|
+
Async::Connection::RoutingConnection.new(connection,
|
|
29
|
+
Util::Futures.join_now_or_else_throw(context.database_name_future, Async::ConnectionContext::PENDING_DATABASE_NAME_EXCEPTION_SUPPLIER),
|
|
30
|
+
context.mode, context.impersonated_user, handler)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def verify_connectivity
|
|
36
|
+
supports_multi_db?.then_flat do |supports|
|
|
37
|
+
@routing_tables.ensure_routing_table(Async::ImmutableConnectionContext.simple(supports)) do |_, error|
|
|
38
|
+
if error.is_a? Exceptions::ServiceUnavailableException
|
|
39
|
+
raise Exceptions::ServiceUnavailableException.new(
|
|
40
|
+
'Unable to connect to database management service, ensure the database is running and that there is a working network connection to it.',
|
|
41
|
+
error)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def supports_multi_db?
|
|
48
|
+
begin
|
|
49
|
+
addresses = @rediscovery.resolve
|
|
50
|
+
rescue StandardError => error
|
|
51
|
+
return Util::Futures.failed_future(error)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
result = Util::Futures.completed_with_null
|
|
55
|
+
base_error = Exceptions::ServiceUnavailableException.new("Failed to perform multi-databases feature detection with the following servers: #{addresses}")
|
|
56
|
+
|
|
57
|
+
addresses.each do |address|
|
|
58
|
+
result = Util::Futures.on_error_continue(result, base_error) do |error|
|
|
59
|
+
# We fail fast on security errors
|
|
60
|
+
if error.is_a? Exceptions::SecurityException
|
|
61
|
+
Util::Futures.failed_future(error)
|
|
62
|
+
else
|
|
63
|
+
private_suports_multi_db?(address)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
Util::Futures.on_error_continue(result, base_error) do |error|
|
|
69
|
+
# If we failed with security errors, then we rethrow the security error out, otherwise we throw the chained errors.
|
|
70
|
+
Util::Futures.failed_future((error.is_a? Exceptions::SecurityException) ? error : base_error)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def private_suports_multi_db?(address)
|
|
77
|
+
@connection_pool.acquire(address).then_flat do |conn|
|
|
78
|
+
supports_multi_database = Messaging::Request::MultiDatabaseUtil.supports_multi_database(conn)
|
|
79
|
+
conn.release.then_apply(-> (_ignored) { supports_multi_database })
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def acquire(mode, routing_table, result = nil, attempt_errors = nil)
|
|
84
|
+
unless result.present? && attempt_errors.present?
|
|
85
|
+
result = java.util.concurrent.CompletableFuture.new
|
|
86
|
+
attempt_exceptions = []
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
addresses = addresses_by_mode(mode, routing_table)
|
|
90
|
+
address = select_address(mode, addresses)
|
|
91
|
+
|
|
92
|
+
if address.nil?
|
|
93
|
+
completion_error = Exceptions::SessionExpiredException.new(CONNECTION_ACQUISITION_COMPLETION_EXCEPTION_MESSAGE % [mode, routing_table])
|
|
94
|
+
attempt_errors.each { completion_error::add_suppressed }
|
|
95
|
+
|
|
96
|
+
@log.error(CONNECTION_ACQUISITION_COMPLETION_FAILURE_MESSAGE % completion_error)
|
|
97
|
+
result.complete_exceptionally(completion_error)
|
|
98
|
+
return
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
@connection_pool.acquire(address).when_complete do |connection, completion_error|
|
|
102
|
+
error = Util::Futures.completion_exception_cause(completion_error)
|
|
103
|
+
|
|
104
|
+
if error.nil?
|
|
105
|
+
result.complete(connection)
|
|
106
|
+
else
|
|
107
|
+
if !error.is_a? Exceptions::ServiceUnavailableException
|
|
108
|
+
result.complete_exceptionally(error)
|
|
109
|
+
else
|
|
110
|
+
attempt_message = CONNECTION_ACQUISITION_ATTEMPT_FAILURE_MESSAGE % address
|
|
111
|
+
@log.warn(attempt_message)
|
|
112
|
+
@log.debug(attempt_message, error)
|
|
113
|
+
attempt_errors << error
|
|
114
|
+
routing_table.forget(address)
|
|
115
|
+
@event_executor_group.next.execute(-> () { acquire(mode, routing_table, result, attempt_errors) })
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def addresses_by_mode(mode, routing_table)
|
|
122
|
+
case mode
|
|
123
|
+
when READ
|
|
124
|
+
routing_table.readers
|
|
125
|
+
when WRITE
|
|
126
|
+
routing_table.writers
|
|
127
|
+
else
|
|
128
|
+
raise unknown_mode mode
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def select_address(mode, addresses)
|
|
133
|
+
case mode
|
|
134
|
+
when READ
|
|
135
|
+
@load_balancing_strategy.select_reader(addresses)
|
|
136
|
+
when WRITE
|
|
137
|
+
@load_balancing_strategy.select_writer(addresses)
|
|
138
|
+
else
|
|
139
|
+
raise unknown_mode mode
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def create_routing_tables(connection_pool, rediscovery, settings, clock, logger)
|
|
144
|
+
RoutingTableRegistryImpl.new(connection_pool, rediscovery, clock, logger, DurationNormalizer.milliseconds(settings.routing_table_purge_delay))
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def create_rediscovery(event_executor_group, initial_router, resolver, settings, clock, logger, domain_name_resolver)
|
|
148
|
+
cluster_composition_provider = RoutingProcedureClusterCompositionProvider.new(clock, settings.routing_context)
|
|
149
|
+
RediscoveryImpl.new(initial_router, settings, cluster_composition_provider, event_executor_group, resolver, logger, domain_name_resolver)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def unknown_mode(mode)
|
|
153
|
+
ArgumentError.new("Mode '#{mode}' is not supported")
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Neo4j::Driver
|
|
2
|
+
module Internal
|
|
3
|
+
module Cluster
|
|
4
|
+
module Loadbalancing
|
|
5
|
+
class RoundRobinArrayIndex < Concurrent::AtomicFixnum
|
|
6
|
+
def next(array_length)
|
|
7
|
+
(increment - 1) % array_length if array_length.positive?
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Neo4j::Driver
|
|
2
|
+
module Internal
|
|
3
|
+
module Cluster
|
|
4
|
+
|
|
5
|
+
# This implementation of the {@link RoutingProcedureRunner} works with multi database versions of Neo4j calling
|
|
6
|
+
# the procedure `dbms.routing.getRoutingTable`
|
|
7
|
+
class MultiDatabasesRoutingProcedureRunner < SingleDatabaseRoutingProcedureRunner
|
|
8
|
+
DATABASE_NAME = 'database'
|
|
9
|
+
MULTI_DB_GET_ROUTING_TABLE = "CALL dbms.routing.getRoutingTable($%s, $%s)" % [SingleDatabaseRoutingProcedureRunner::ROUTING_CONTEXT, DATABASE_NAME]
|
|
10
|
+
|
|
11
|
+
def initialize(context)
|
|
12
|
+
super(context)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def bookmark_holder(bookmark)
|
|
18
|
+
ReadOnlyBookmarkHolder.new(bookmark)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def procedure_query(server_version, database_name)
|
|
22
|
+
map = {}
|
|
23
|
+
map[SingleDatabaseRoutingProcedureRunner::ROUTING_CONTEXT] = Values.value(context.to_map)
|
|
24
|
+
map[DATABASE_NAME] = Values.value(database_name.database_name)
|
|
25
|
+
Query.new(MULTI_DB_GET_ROUTING_TABLE, Values.value(map))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def connection(connection)
|
|
29
|
+
Async::Connection::DirectConnection.new(connection, DatabaseNameUtil::SYSTEM_DATABASE, AccessMode::READ, nil)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
module Neo4j::Driver
|
|
2
|
+
module Internal
|
|
3
|
+
module Cluster
|
|
4
|
+
class RediscoveryImpl
|
|
5
|
+
NO_ROUTERS_AVAILABLE = "Could not perform discovery for database '%s'. No routing server available."
|
|
6
|
+
RECOVERABLE_ROUTING_ERROR = "Failed to update routing table with server '%s'."
|
|
7
|
+
RECOVERABLE_DISCOVERY_ERROR_WITH_SERVER = "Received a recoverable discovery error with server '%s', will continue discovery with other routing servers if available. Complete failure is reported separately from this entry."
|
|
8
|
+
INVALID_BOOKMARK_CODE = 'Neo.ClientError.Transaction.InvalidBookmark'
|
|
9
|
+
INVALID_BOOKMARK_MIXTURE_CODE = 'Neo.ClientError.Transaction.InvalidBookmarkMixture'
|
|
10
|
+
|
|
11
|
+
def initialize(initial_router, settings, provider, event_executor_group, resolver, logger, domain_name_resolver)
|
|
12
|
+
@initial_router = initial_router
|
|
13
|
+
@settings = settings
|
|
14
|
+
@log = logger
|
|
15
|
+
@provider = provider
|
|
16
|
+
@resolver = resolver
|
|
17
|
+
@event_executor_group = event_executor_group
|
|
18
|
+
@domain_name_resolver = Internal::Validator.require_non_nil!(domain_name_resolver)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Given a database and its current routing table, and the global connection pool, use the global cluster composition provider to fetch a new cluster
|
|
22
|
+
# composition, which would be used to update the routing table of the given database and global connection pool.
|
|
23
|
+
|
|
24
|
+
# @param routingTable current routing table of the given database.
|
|
25
|
+
# @param connectionPool connection pool.
|
|
26
|
+
# @return new cluster composition and an optional set of resolved initial router addresses.
|
|
27
|
+
def lookup_cluster_composition(routing_table, connection_pool, bookmark, impersonated_user, failures = nil, previous_delay = nil, result = nil, base_error = nil)
|
|
28
|
+
result = java.util.concurrent.CompletableFuture.new
|
|
29
|
+
|
|
30
|
+
# if we failed discovery, we will chain all errors into this one.
|
|
31
|
+
base_error = Exceptions::ServiceUnavailableException.new(NO_ROUTERS_AVAILABLE % routing_table.database.description)
|
|
32
|
+
|
|
33
|
+
lookup(routing_table, connection_pool, bookmark, impersonated_user, base_error).when_complete do |composition_lookup_result, completion_error|
|
|
34
|
+
error = Util::Futures.completion_exception_cause(completion_error)
|
|
35
|
+
|
|
36
|
+
if !error.nil?
|
|
37
|
+
result.complete_exceptionally(error)
|
|
38
|
+
elsif !composition_lookup_result.nil?
|
|
39
|
+
result.complete(composition_lookup_result)
|
|
40
|
+
else
|
|
41
|
+
new_failures = failures + 1
|
|
42
|
+
|
|
43
|
+
if new_failures >= @settings.max_routing_failures
|
|
44
|
+
# now we throw our saved error out
|
|
45
|
+
result.complete_exceptionally(base_error)
|
|
46
|
+
else
|
|
47
|
+
next_delay = java.lang.Math.max(@settings.retry_timeout_delay, previous_delay * 2)
|
|
48
|
+
@log.info("Unable to fetch new routing table, will try again in #{next_delay} ms")
|
|
49
|
+
|
|
50
|
+
@event_executor_group.next.schedule(next_delay, java.util.concurrent.TimeUnit::MILLISECONDS) do
|
|
51
|
+
lookup_cluster_composition(routing_table, connection_pool, bookmark, impersonated_user, new_failures, next_delay, result, base_error)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
result
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def resolve
|
|
61
|
+
resolved_addresses = java.util.LinkedList.new
|
|
62
|
+
exception = nil
|
|
63
|
+
|
|
64
|
+
@resolver.resolve(initial_router).each do |server_address|
|
|
65
|
+
begin
|
|
66
|
+
resolve_all_by_domain_name(server_address).unicast_stream.for_each(resolved_addresses::add)
|
|
67
|
+
rescue java.net.UnknownHostException => e
|
|
68
|
+
if exception.nil?
|
|
69
|
+
exception = e
|
|
70
|
+
else
|
|
71
|
+
exception.add_suppressed(e)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# give up only if there are no addresses to work with at all
|
|
77
|
+
if resolved_addresses.empty? && !exception.nil?
|
|
78
|
+
raise exception
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
resolved_addresses
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def lookup(routing_table, connection_pool, bookmark, impersonated_user, base_error)
|
|
87
|
+
composition_stage = if routing_table.prefer_initial_router
|
|
88
|
+
lookup_on_initial_router_then_on_known_routers(routing_table, connection_pool, bookmark, impersonated_user, base_error)
|
|
89
|
+
else
|
|
90
|
+
lookup_on_known_routers_then_on_initial_router(routing_table, connection_pool, bookmark, impersonated_user, base_error)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def lookup_on_known_routers_then_on_initial_router(routing_table, connection_pool, bookmark, impersonated_user, base_error)
|
|
95
|
+
seen_servers = {}
|
|
96
|
+
|
|
97
|
+
lookup_on_known_routers(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error).then_compose do |composition_lookup_result|
|
|
98
|
+
if composition_lookup_result.nil?
|
|
99
|
+
java.util.concurrent.CompletableFuture.completed_future(composition_lookup_result)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
lookup_on_initial_router(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def lookup_on_initial_router_then_on_known_routers(routing_table, connection_pool, bookmark, impersonated_user, base_error)
|
|
107
|
+
seen_servers = [].freeze
|
|
108
|
+
|
|
109
|
+
lookup_on_initial_router(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error).then_compose do |composition_lookup_result|
|
|
110
|
+
if composition_lookup_result.nil?
|
|
111
|
+
java.util.concurrent.CompletableFuture.completed_future(composition_lookup_result)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
lookup_on_known_routers(routing_table, connection_pool, {}, bookmark, impersonated_user, base_error)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def lookup_on_known_routers(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
|
|
119
|
+
result = Util::Futures.completed_with_null
|
|
120
|
+
|
|
121
|
+
routing_table.routers.each do |address|
|
|
122
|
+
result = result.then_compose do |composition|
|
|
123
|
+
if !composition.nil?
|
|
124
|
+
java.util.concurrent.CompletableFuture.completed_future(composition)
|
|
125
|
+
else
|
|
126
|
+
lookup_on_router(address, true, routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
result.then_apply do |composition|
|
|
132
|
+
composition.nil? ? nil : ClusterCompositionLookupResult.new(composition)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def lookup_on_initial_router(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
|
|
137
|
+
begin
|
|
138
|
+
resolved_routers = resolve
|
|
139
|
+
rescue StandardError => error
|
|
140
|
+
Util::Futures.failed_future(error)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
resolved_router_set = [resolved_routers]
|
|
144
|
+
resolved_routers - seen_servers
|
|
145
|
+
|
|
146
|
+
result = Util::Futures.completed_with_null
|
|
147
|
+
|
|
148
|
+
resolved_routers.each do |address|
|
|
149
|
+
result = result.then_compose do |composition|
|
|
150
|
+
if !composition.nil?
|
|
151
|
+
java.util.concurrent.CompletableFuture.completed_future(composition)
|
|
152
|
+
else
|
|
153
|
+
lookup_on_router(address, false, routing_table, connection_pool, nil, bookmark, impersonated_user, base_error)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
result.then_apply do |composition|
|
|
159
|
+
composition.nil? ? nil : ClusterCompositionLookupResult.new(composition, resolved_router_set)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def lookup_on_router(router_address, resolve_address, routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
|
|
164
|
+
address_future = java.util.concurrent.CompletableFuture.completed_future(router_address)
|
|
165
|
+
|
|
166
|
+
address_future.then_apply do |address|
|
|
167
|
+
resolve_address ? resolve_by_domain_name_or_throw_completion_exception(address, routing_table) : address
|
|
168
|
+
end.then_apply do |address|
|
|
169
|
+
add_and_return(seen_servers, address)
|
|
170
|
+
end.then_compose do
|
|
171
|
+
connection_pool::acquire
|
|
172
|
+
end.then_apply do |connection|
|
|
173
|
+
ImpersonationUtil.ensure_impersonation_support(connection, impersonated_user)
|
|
174
|
+
end.then_compose do |connection|
|
|
175
|
+
@provider.get_cluster_composition(connection, routing_table.database, bookmark, impersonated_user)
|
|
176
|
+
end.handle do |response, error|
|
|
177
|
+
cause = Util::Futures.completion_exception_cause(error)
|
|
178
|
+
|
|
179
|
+
if !cause.nil?
|
|
180
|
+
handle_routing_procedure_error(cause, routing_table, router_address, base_error)
|
|
181
|
+
else
|
|
182
|
+
response
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def handle_routing_procedure_error(error, routing_table, router_address, base_error)
|
|
188
|
+
raise java.util.concurrent.CompletionException, error if must_abort_discovery(error)
|
|
189
|
+
|
|
190
|
+
# Retriable error happened during discovery.
|
|
191
|
+
discovery_error = Exceptions::DiscoveryException.new(RECOVERABLE_ROUTING_ERROR % router_address, error)
|
|
192
|
+
Util::Futures.combine_errors(base_error, discovery_error) # we record each failure here
|
|
193
|
+
warning_message = RECOVERABLE_DISCOVERY_ERROR_WITH_SERVER % router_address
|
|
194
|
+
@log.warn(warning_message)
|
|
195
|
+
@log.debug(warning_message, discovery_error)
|
|
196
|
+
routing_table.forget(router_address)
|
|
197
|
+
nil
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def must_abort_discovery(throwable)
|
|
201
|
+
abort = if !(throwable.is_a? Exceptions::AuthorizationExpiredException) && (throwable.is_a? Exceptions::SecurityException)
|
|
202
|
+
true
|
|
203
|
+
elsif throwable.is_a? Exceptions::FatalDiscoveryException
|
|
204
|
+
true
|
|
205
|
+
elsif throwable.is_a? Exceptions::IllegalStateException && Spi::ConnectionPool::CONNECTION_POOL_CLOSED_ERROR_MESSAGE == throwable.message
|
|
206
|
+
true
|
|
207
|
+
elsif throwable.is_a? Exceptions::ClientException
|
|
208
|
+
code = throwable.code
|
|
209
|
+
INVALID_BOOKMARK_CODE.eql?(code) || INVALID_BOOKMARK_MIXTURE_CODE.eql?(code)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def add_and_return(collection, element)
|
|
214
|
+
collection << element unless collection.nil?
|
|
215
|
+
|
|
216
|
+
element
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def resolve_by_domain_name_or_throw_completion_exception(address, routing_table)
|
|
220
|
+
begin
|
|
221
|
+
resolved_address = resolve_all_by_domain_name(address)
|
|
222
|
+
routing_table.replace_router_if_present(address, resolved_address)
|
|
223
|
+
|
|
224
|
+
resolved_address.unicast_stream.find_first.or_else_throw do
|
|
225
|
+
Exceptions::IllegalStateException.new('Unexpected condition, the ResolvedBoltServerAddress must always have at least one unicast address')
|
|
226
|
+
end
|
|
227
|
+
rescue StandardError => e
|
|
228
|
+
raise java.util.concurrent.CompletionException, e
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def resolve_all_by_domain_name(address)
|
|
233
|
+
ResolvedBoltServerAddress.new(address.host, address.port, domain_name_resolver.resolve(address.host))
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Neo4j::Driver
|
|
2
|
+
module Internal
|
|
3
|
+
module Cluster
|
|
4
|
+
# This implementation of the {@link RoutingProcedureRunner} access the routing procedure
|
|
5
|
+
# through the bolt's ROUTE message.
|
|
6
|
+
class RouteMessageRoutingProcedureRunner
|
|
7
|
+
attr_writer :routing_table
|
|
8
|
+
|
|
9
|
+
def initialize(routing_context)
|
|
10
|
+
@routing_context = routing_context.to_h
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run(connection, database_name, bookmark, impersonated_user)
|
|
14
|
+
direct_connection = to_direct_connection(connection, database_name, impersonated_user)
|
|
15
|
+
direct_connection.write_and_flush(
|
|
16
|
+
Messaging::Request::RouteMessage.new(@routing_context, bookmark, database_name.database_name,
|
|
17
|
+
impersonated_user),
|
|
18
|
+
Handlers::RouteMessageResponseHandler.new(self))
|
|
19
|
+
RoutingProcedureResponse.new(query(database_name), to_record(routing_table))
|
|
20
|
+
rescue => e
|
|
21
|
+
RoutingProcedureResponse.new(query(database_name), e)
|
|
22
|
+
ensure
|
|
23
|
+
direct_connection.release
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def to_record(routing_table)
|
|
29
|
+
InternalRecord.new(routing_table.keys, routing_table.values)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def to_direct_connection(connection, database_name, impersonated_user)
|
|
33
|
+
Async::Connection::DirectConnection.new(connection, database_name, AccessMode::READ, impersonated_user)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def query(database_name)
|
|
37
|
+
Query.new('ROUTE $routing_context $database_name', routing_context: @routing_context,
|
|
38
|
+
database_name: database_name.database_name)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module Neo4j::Driver
|
|
2
|
+
module Internal
|
|
3
|
+
module Cluster
|
|
4
|
+
class RoutingContext
|
|
5
|
+
include Scheme
|
|
6
|
+
EMPTY = new
|
|
7
|
+
ROUTING_ADDRESS_KEY = :address
|
|
8
|
+
|
|
9
|
+
def initialize(uri = nil)
|
|
10
|
+
if uri
|
|
11
|
+
@server_routing_enabled = routing_scheme?(uri.scheme)
|
|
12
|
+
@context = parse_parameters(uri).freeze
|
|
13
|
+
else
|
|
14
|
+
@server_routing_enabled = true
|
|
15
|
+
@context = {}
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def defined?
|
|
20
|
+
@context.size > 1
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_h
|
|
24
|
+
@context
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def server_routing_enabled?
|
|
28
|
+
@server_routing_enabled
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
"RoutingContext #{@context} ServerRoutingEnabled=#{@server_routing_enabled}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def parse_parameters(uri)
|
|
38
|
+
query = uri.query
|
|
39
|
+
address = "#{uri.host}:#{uri.port || BoltServerAddress::DEFAULT_PORT}"
|
|
40
|
+
parameters = { ROUTING_ADDRESS_KEY => address }
|
|
41
|
+
return parameters if query.blank?
|
|
42
|
+
|
|
43
|
+
pairs = query.split('&')
|
|
44
|
+
pairs.each do |pair|
|
|
45
|
+
key_value = pair.split('=')
|
|
46
|
+
|
|
47
|
+
if key_value.size != 2
|
|
48
|
+
raise ArgumentError, "Invalid parameters: '#{pair}' in URI '#{uri}'"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
key = trim_and_verify_key(key_value[0], 'key', uri)
|
|
52
|
+
if parameters.key?(key)
|
|
53
|
+
raise ArgumentError, "Duplicated query parameters with key '#{key}' in URI '#{uri}'"
|
|
54
|
+
end
|
|
55
|
+
parameters[key] = trim_and_verify(key_value[1], 'value', uri)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
parameters
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def trim_and_verify_key(s, key, uri)
|
|
62
|
+
trim_and_verify(s, key, uri).tap do |trimmed|
|
|
63
|
+
if trimmed == ROUTING_ADDRESS_KEY
|
|
64
|
+
raise ArgumentError, "The key 'address' is reserved for routing context."
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def trim_and_verify(string, name, uri)
|
|
70
|
+
string.strip.tap do |result|
|
|
71
|
+
raise ArgumentError, "Illegal empty #{name} in URI query '#{uri}'" if result.empty?
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|