neo4j-ruby-driver 1.7.4 → 4.4.0
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 +37 -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/driver/types/time.rb +4 -2
- 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 +89 -0
- data/ruby/neo4j/driver/graph_database.rb +80 -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 +83 -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 +171 -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 +194 -0
- data/ruby/neo4j/driver/internal/async/network_session.rb +150 -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 +62 -0
- data/ruby/neo4j/driver/internal/async/pool/channel_pool.rb +31 -0
- data/ruby/neo4j/driver/internal/async/pool/channel_tracker.rb +135 -0
- data/ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb +156 -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/network_connection_factory.rb +21 -0
- data/ruby/neo4j/driver/internal/async/pool/pool_settings.rb +34 -0
- data/ruby/neo4j/driver/internal/async/pool/timed_stack.rb +15 -0
- data/ruby/neo4j/driver/internal/async/result_cursors_holder.rb +17 -0
- data/ruby/neo4j/driver/internal/async/unmanaged_transaction.rb +212 -0
- data/ruby/neo4j/driver/internal/bookmark_holder.rb +9 -0
- data/ruby/neo4j/driver/internal/cluster/cluster_composition.rb +48 -0
- data/ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb +14 -0
- data/ruby/neo4j/driver/internal/cluster/cluster_routing_table.rb +122 -0
- data/ruby/neo4j/driver/internal/cluster/identity_resolver.rb +10 -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 +125 -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 +31 -0
- data/ruby/neo4j/driver/internal/cluster/rediscovery_impl.rb +147 -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 +60 -0
- data/ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb +35 -0
- data/ruby/neo4j/driver/internal/cluster/routing_settings.rb +24 -0
- data/ruby/neo4j/driver/internal/cluster/routing_table_handler_impl.rb +95 -0
- data/ruby/neo4j/driver/internal/cluster/routing_table_registry_impl.rb +121 -0
- data/ruby/neo4j/driver/internal/cluster/single_database_routing_procedure_runner.rb +73 -0
- data/ruby/neo4j/driver/internal/connection_settings.rb +16 -0
- data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +55 -0
- data/ruby/neo4j/driver/internal/cursor/async_result_cursor_only_factory.rb +24 -0
- data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +61 -0
- data/ruby/neo4j/driver/internal/cursor/result_cursor_factory_impl.rb +24 -0
- data/ruby/neo4j/driver/internal/cursor/rx_result_cursor_impl.rb +110 -0
- data/ruby/neo4j/driver/internal/database_name_util.rb +37 -0
- data/ruby/neo4j/driver/internal/default_bookmark_holder.rb +9 -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 +126 -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 +30 -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 +199 -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 +168 -0
- data/ruby/neo4j/driver/internal/handlers/pulln/basic_pull_response_handler.rb +298 -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 +25 -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 +38 -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 +36 -0
- data/ruby/neo4j/driver/internal/internal_database_name.rb +9 -0
- data/ruby/neo4j/driver/internal/internal_driver.rb +74 -0
- data/ruby/neo4j/driver/internal/internal_entity.rb +20 -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 +49 -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 +48 -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 +24 -0
- data/ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb +22 -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 +25 -0
- data/ruby/neo4j/driver/internal/messaging/request/begin_message.rb +25 -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 +28 -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 +49 -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 +82 -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 +17 -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 +20 -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 +15 -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/read_only_bookmark_holder.rb +13 -0
- data/ruby/neo4j/driver/internal/resolved_bolt_server_address.rb +35 -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 +48 -0
- data/ruby/neo4j/driver/internal/security_setting.rb +66 -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 +107 -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/result_holder.rb +72 -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_address.rb +9 -0
- data/ruby/neo4j/driver/query.rb +48 -0
- data/ruby/neo4j/driver/records.rb +13 -0
- data/ruby/neo4j/driver/transaction_config.rb +50 -0
- data/ruby/neo4j/driver/values.rb +26 -0
- data/{lib → ruby}/neo4j/driver/version.rb +1 -1
- data/ruby/neo4j/driver.rb +29 -0
- metadata +264 -101
- 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 -125
- 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
|
+
if size == 0
|
32
|
+
@log.debug("Unable to select #{address_type}, no known addresses given")
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
# choose start index for iteration in round-robin fashion
|
37
|
+
start_index = addresses_index.next(size)
|
38
|
+
index = start_index
|
39
|
+
|
40
|
+
least_connected_address = nil
|
41
|
+
least_active_connections = nil
|
42
|
+
|
43
|
+
# iterate over the array to find the least connected address
|
44
|
+
addresses = addresses.to_a
|
45
|
+
loop do
|
46
|
+
address = addresses[index]
|
47
|
+
active_connections = @connection_pool.in_use_connections(address)
|
48
|
+
|
49
|
+
if least_active_connections.nil? || 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 + 1) % size
|
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,125 @@
|
|
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
|
+
delegate :close, to: :@connection_pool
|
12
|
+
|
13
|
+
def initialize(initial_router, settings, connection_pool, event_executor_group, logger, load_balancing_strategy, resolver, &domain_name_resolver)
|
14
|
+
clock = Util::Clock::System
|
15
|
+
@connection_pool = connection_pool
|
16
|
+
@rediscovery = create_rediscovery(event_executor_group, initial_router, resolver, settings, clock, logger, domain_name_resolver)
|
17
|
+
@routing_tables = create_routing_tables(connection_pool, @rediscovery, settings, clock, logger)
|
18
|
+
@load_balancing_strategy = load_balancing_strategy
|
19
|
+
@event_executor_group = event_executor_group
|
20
|
+
@log = logger
|
21
|
+
end
|
22
|
+
|
23
|
+
def acquire_connection(context)
|
24
|
+
handler = @routing_tables.ensure_routing_table(context)
|
25
|
+
connection = acquire(context.mode, handler.routing_table)
|
26
|
+
Async::Connection::RoutingConnection.new(connection, context.database_name, context.mode,
|
27
|
+
context.impersonated_user, handler)
|
28
|
+
end
|
29
|
+
|
30
|
+
def verify_connectivity
|
31
|
+
@routing_tables.ensure_routing_table(Async::ImmutableConnectionContext.simple(supports_multi_db?))
|
32
|
+
rescue Exceptions::ServiceUnavailableException
|
33
|
+
raise Exceptions::ServiceUnavailableException,
|
34
|
+
'Unable to connect to database management service, ensure the database is running and that there is a working network connection to it.'
|
35
|
+
end
|
36
|
+
|
37
|
+
def routing_table_registry
|
38
|
+
@routing_tables
|
39
|
+
end
|
40
|
+
|
41
|
+
def supports_multi_db?
|
42
|
+
addresses = @rediscovery.resolve
|
43
|
+
base_error = Exceptions::ServiceUnavailableException.new("Failed to perform multi-databases feature detection with the following servers: #{addresses}")
|
44
|
+
addresses.each do |address|
|
45
|
+
return private_suports_multi_db?(address)
|
46
|
+
rescue Exceptions::SecurityException
|
47
|
+
raise
|
48
|
+
rescue => error
|
49
|
+
Util::Futures.combine_errors(base_error, error)
|
50
|
+
end
|
51
|
+
|
52
|
+
raise base_error
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def private_suports_multi_db?(address)
|
58
|
+
conn = @connection_pool.acquire(address)
|
59
|
+
Messaging::Request::MultiDatabaseUtil.supports_multi_database?(conn)
|
60
|
+
ensure
|
61
|
+
conn&.release
|
62
|
+
end
|
63
|
+
|
64
|
+
def acquire(mode, routing_table, attempt_errors = [])
|
65
|
+
addresses = addresses_by_mode(mode, routing_table)
|
66
|
+
address = select_address(mode, addresses)
|
67
|
+
|
68
|
+
unless address
|
69
|
+
error = Exceptions::SessionExpiredException.new(CONNECTION_ACQUISITION_COMPLETION_EXCEPTION_MESSAGE % [mode, routing_table])
|
70
|
+
attempt_errors.each(&error.method(:add_suppressed))
|
71
|
+
@log.error(CONNECTION_ACQUISITION_COMPLETION_FAILURE_MESSAGE)
|
72
|
+
@log.error(error)
|
73
|
+
raise error
|
74
|
+
end
|
75
|
+
|
76
|
+
begin
|
77
|
+
@connection_pool.acquire(address)
|
78
|
+
rescue Exceptions::ServiceUnavailableException => error
|
79
|
+
@log.warn { CONNECTION_ACQUISITION_ATTEMPT_FAILURE_MESSAGE % address }
|
80
|
+
@log.debug(error)
|
81
|
+
attempt_errors << error
|
82
|
+
routing_table.forget(address)
|
83
|
+
acquire(mode, routing_table, attempt_errors)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def addresses_by_mode(mode, routing_table)
|
88
|
+
case mode
|
89
|
+
when AccessMode::READ
|
90
|
+
routing_table.readers
|
91
|
+
when AccessMode::WRITE
|
92
|
+
routing_table.writers
|
93
|
+
else
|
94
|
+
raise unknown_mode mode
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def select_address(mode, addresses)
|
99
|
+
case mode
|
100
|
+
when AccessMode::READ
|
101
|
+
@load_balancing_strategy.select_reader(addresses)
|
102
|
+
when AccessMode::WRITE
|
103
|
+
@load_balancing_strategy.select_writer(addresses)
|
104
|
+
else
|
105
|
+
raise unknown_mode mode
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def create_routing_tables(connection_pool, rediscovery, settings, clock, logger)
|
110
|
+
RoutingTableRegistryImpl.new(connection_pool, rediscovery, clock, logger, settings.routing_table_purge_delay)
|
111
|
+
end
|
112
|
+
|
113
|
+
def create_rediscovery(event_executor_group, initial_router, resolver, settings, clock, logger, domain_name_resolver)
|
114
|
+
cluster_composition_provider = RoutingProcedureClusterCompositionProvider.new(clock, settings.routing_context)
|
115
|
+
RediscoveryImpl.new(initial_router, settings, cluster_composition_provider, event_executor_group, resolver, logger, domain_name_resolver)
|
116
|
+
end
|
117
|
+
|
118
|
+
def unknown_mode(mode)
|
119
|
+
ArgumentError.new("Mode '#{mode}' is not supported")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
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,31 @@
|
|
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
|
+
private
|
12
|
+
|
13
|
+
def bookmark_holder(bookmark)
|
14
|
+
ReadOnlyBookmarkHolder.new(bookmark)
|
15
|
+
end
|
16
|
+
|
17
|
+
def procedure_query(server_version, database_name)
|
18
|
+
map = {
|
19
|
+
SingleDatabaseRoutingProcedureRunner::ROUTING_CONTEXT => @context.to_h,
|
20
|
+
DATABASE_NAME => database_name.database_name
|
21
|
+
}
|
22
|
+
Query.new(MULTI_DB_GET_ROUTING_TABLE, **map)
|
23
|
+
end
|
24
|
+
|
25
|
+
def connection(connection)
|
26
|
+
Async::Connection::DirectConnection.new(connection, DatabaseNameUtil::SYSTEM_DATABASE, AccessMode::READ, nil)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,147 @@
|
|
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(
|
28
|
+
routing_table, connection_pool, bookmark, impersonated_user,
|
29
|
+
failures = 0,
|
30
|
+
previous_delay = 0,
|
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) ||
|
34
|
+
if failures > @settings.max_routing_failures
|
35
|
+
# now we throw our saved error out
|
36
|
+
raise base_error
|
37
|
+
else
|
38
|
+
next_delay = [@settings.retry_timeout_delay, previous_delay * 2].max
|
39
|
+
@log.info("Unable to fetch new routing table, will try again in #{next_delay} ms")
|
40
|
+
sleep next_delay
|
41
|
+
lookup_cluster_composition(routing_table, connection_pool, bookmark, impersonated_user, failures + 1, next_delay, base_error)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def resolve
|
46
|
+
exception = nil
|
47
|
+
|
48
|
+
resolved_addresses = @resolver.call(@initial_router).flat_map do |server_address|
|
49
|
+
resolve_all_by_domain_name(server_address).unicast_stream
|
50
|
+
# rescue java.net.UnknownHostException => e
|
51
|
+
rescue SocketError => e
|
52
|
+
exception ||= e
|
53
|
+
[]
|
54
|
+
end
|
55
|
+
|
56
|
+
# give up only if there are no addresses to work with at all
|
57
|
+
raise exception if resolved_addresses.empty? && exception
|
58
|
+
|
59
|
+
resolved_addresses
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def lookup(routing_table, connection_pool, bookmark, impersonated_user, base_error)
|
65
|
+
if routing_table.prefer_initial_router
|
66
|
+
lookup_on_initial_router_then_on_known_routers(routing_table, connection_pool, bookmark, impersonated_user, base_error)
|
67
|
+
else
|
68
|
+
lookup_on_known_routers_then_on_initial_router(routing_table, connection_pool, bookmark, impersonated_user, base_error)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def lookup_on_known_routers_then_on_initial_router(routing_table, connection_pool, bookmark, impersonated_user, base_error)
|
73
|
+
seen_servers = Set.new
|
74
|
+
lookup_on_known_routers(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error) ||
|
75
|
+
lookup_on_initial_router(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
|
76
|
+
end
|
77
|
+
|
78
|
+
def lookup_on_initial_router_then_on_known_routers(routing_table, connection_pool, bookmark, impersonated_user, base_error)
|
79
|
+
lookup_on_initial_router(routing_table, connection_pool, Set.new, bookmark, impersonated_user, base_error) ||
|
80
|
+
lookup_on_known_routers(routing_table, connection_pool, Set.new, bookmark, impersonated_user, base_error)
|
81
|
+
end
|
82
|
+
|
83
|
+
def lookup_on_known_routers(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
|
84
|
+
routing_table.routers.lazy.map do |address|
|
85
|
+
lookup_on_router(address, true, routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
|
86
|
+
end.first&.then(&ClusterCompositionLookupResult.method(:new))
|
87
|
+
end
|
88
|
+
|
89
|
+
def lookup_on_initial_router(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
|
90
|
+
resolved_routers = resolve
|
91
|
+
(resolved_routers - seen_servers.to_a).lazy.filter_map do |address|
|
92
|
+
lookup_on_router(address, false, routing_table, connection_pool, nil, bookmark,
|
93
|
+
impersonated_user, base_error)
|
94
|
+
end.first&.then { |composition| ClusterCompositionLookupResult.new(composition, Set.new(resolved_routers)) }
|
95
|
+
end
|
96
|
+
|
97
|
+
def lookup_on_router(router_address, resolve_address, routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
|
98
|
+
address = resolve_address ? resolve_by_domain_name_or_throw_completion_exception(router_address, routing_table) : router_address
|
99
|
+
seen_servers&.send(:<<, address)
|
100
|
+
connection = connection_pool.acquire(address)
|
101
|
+
ImpersonationUtil.ensure_impersonation_support(connection, impersonated_user)
|
102
|
+
@provider.get_cluster_composition(connection, routing_table.database, bookmark, impersonated_user)
|
103
|
+
rescue => error
|
104
|
+
handle_routing_procedure_error(error, routing_table, router_address, base_error)
|
105
|
+
end
|
106
|
+
|
107
|
+
def handle_routing_procedure_error(error, routing_table, router_address, base_error)
|
108
|
+
raise error if must_abort_discovery(error)
|
109
|
+
|
110
|
+
# Retriable error happened during discovery.
|
111
|
+
discovery_error = Exceptions::DiscoveryException.new(nil, RECOVERABLE_ROUTING_ERROR % router_address, error)
|
112
|
+
Util::Futures.combine_errors(base_error, discovery_error) # we record each failure here
|
113
|
+
warning_message = RECOVERABLE_DISCOVERY_ERROR_WITH_SERVER % router_address
|
114
|
+
@log.warn(warning_message)
|
115
|
+
@log.debug(discovery_error)
|
116
|
+
routing_table.forget(router_address)
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
|
120
|
+
def must_abort_discovery(error)
|
121
|
+
!error.is_a?(Exceptions::AuthorizationExpiredException) && error.is_a?(Exceptions::SecurityException) ||
|
122
|
+
error.is_a?(Exceptions::FatalDiscoveryException) ||
|
123
|
+
error.is_a?(Exceptions::IllegalStateException) &&
|
124
|
+
Spi::ConnectionPool::CONNECTION_POOL_CLOSED_ERROR_MESSAGE == error.message ||
|
125
|
+
error.is_a?(Exceptions::ClientException) &&
|
126
|
+
[INVALID_BOOKMARK_CODE, INVALID_BOOKMARK_MIXTURE_CODE].include?(error.code) ||
|
127
|
+
# Not sure why this is not im java
|
128
|
+
!error.is_a?(Exceptions::Neo4jException) ||
|
129
|
+
Util::ErrorUtil.fatal?(error)
|
130
|
+
end
|
131
|
+
|
132
|
+
def resolve_by_domain_name_or_throw_completion_exception(address, routing_table)
|
133
|
+
resolved_address = resolve_all_by_domain_name(address)
|
134
|
+
routing_table.replace_router_if_present(address, resolved_address)
|
135
|
+
|
136
|
+
resolved_address.unicast_stream.first or
|
137
|
+
raise Exceptions::IllegalStateException,
|
138
|
+
'Unexpected condition, the ResolvedBoltServerAddress must always have at least one unicast address'
|
139
|
+
end
|
140
|
+
|
141
|
+
def resolve_all_by_domain_name(address)
|
142
|
+
ResolvedBoltServerAddress.new(address.host, address.port, *@domain_name_resolver.call(address.host))
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
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), records: [to_record(@routing_table)])
|
20
|
+
rescue => e
|
21
|
+
RoutingProcedureResponse.new(query(database_name), error: 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
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Neo4j::Driver
|
2
|
+
module Internal
|
3
|
+
module Cluster
|
4
|
+
class RoutingProcedureClusterCompositionProvider
|
5
|
+
PROTOCOL_ERROR_MESSAGE = "Failed to parse '%s' result received from server due to "
|
6
|
+
|
7
|
+
def initialize(_clock, routing_context)
|
8
|
+
@single_database_routing_procedure_runner = SingleDatabaseRoutingProcedureRunner.new(routing_context)
|
9
|
+
@multi_database_routing_procedure_runner = MultiDatabasesRoutingProcedureRunner.new(routing_context)
|
10
|
+
@route_message_routing_procedure_runner = RouteMessageRoutingProcedureRunner.new(routing_context)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_cluster_composition(connection, database_name, bookmark, impersonated_user)
|
14
|
+
runner = if Messaging::Request::MultiDatabaseUtil.supports_route_message?(connection)
|
15
|
+
@route_message_routing_procedure_runner
|
16
|
+
elsif Messaging::Request::MultiDatabaseUtil.supports_multi_database?(connection)
|
17
|
+
@multi_database_routing_procedure_runner
|
18
|
+
else
|
19
|
+
@single_database_routing_procedure_runner
|
20
|
+
end
|
21
|
+
|
22
|
+
process_routing_response(runner.run(connection, database_name, bookmark, impersonated_user))
|
23
|
+
end
|
24
|
+
|
25
|
+
def process_routing_response(response)
|
26
|
+
unless response.success?
|
27
|
+
raise response.error, "Failed to run '#{invoked_procedure_string(response)}' on server. Please make sure that there is a Neo4j server or cluster up running."
|
28
|
+
end
|
29
|
+
|
30
|
+
records = response.records
|
31
|
+
|
32
|
+
# the record size is wrong
|
33
|
+
if records.size != 1
|
34
|
+
raise Exceptions::ProtocolException, "#{PROTOCOL_ERROR_MESSAGE % invoked_procedure_string(response)} records received '#{records.size}' is too few or too many."
|
35
|
+
end
|
36
|
+
|
37
|
+
# failed to parse the record
|
38
|
+
begin
|
39
|
+
cluster = ClusterComposition.parse(records[0], Time.now)
|
40
|
+
rescue Exceptions::Value::ValueException => e
|
41
|
+
raise Exceptions::ProtocolException, "#{PROTOCOL_ERROR_MESSAGE % invoked_procedure_string(response)} unparsable record received. #{e}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# the cluster result is not a legal reply
|
45
|
+
if !cluster.has_routers_and_readers?
|
46
|
+
raise Exceptions::ProtocolException, "#{PROTOCOL_ERROR_MESSAGE % invoked_procedure_string(response)} no router or reader found in response."
|
47
|
+
end
|
48
|
+
|
49
|
+
# all good
|
50
|
+
cluster
|
51
|
+
end
|
52
|
+
|
53
|
+
def invoked_procedure_string(response)
|
54
|
+
query = response.procedure
|
55
|
+
"#{query.text} #{query.parameters}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Neo4j::Driver
|
2
|
+
module Internal
|
3
|
+
module Cluster
|
4
|
+
class RoutingProcedureResponse
|
5
|
+
attr_reader :procedure
|
6
|
+
|
7
|
+
def initialize(procedure, records: nil, error: nil)
|
8
|
+
@procedure = procedure
|
9
|
+
@records = records
|
10
|
+
@error = error
|
11
|
+
end
|
12
|
+
|
13
|
+
def success?
|
14
|
+
!@records.nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
def records
|
18
|
+
if success?
|
19
|
+
@records
|
20
|
+
else
|
21
|
+
raise Exceptions::IllegalStateException, "Can't access records of a failed result #{@error}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def error
|
26
|
+
if success?
|
27
|
+
raise Exceptions::IllegalStateException, "Can't access error of a succeeded result #{@records}"
|
28
|
+
else
|
29
|
+
@error
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Neo4j::Driver
|
2
|
+
module Internal
|
3
|
+
module Cluster
|
4
|
+
class RoutingSettings
|
5
|
+
attr_reader :max_routing_failures, :retry_timeout_delay, :routing_context, :routing_table_purge_delay
|
6
|
+
|
7
|
+
def initialize(max_routing_failures, retry_timeout_delay, routing_table_purge_delay,
|
8
|
+
routing_context = RoutingContext::EMPTY)
|
9
|
+
@max_routing_failures = max_routing_failures
|
10
|
+
@retry_timeout_delay = retry_timeout_delay
|
11
|
+
@routing_context = routing_context
|
12
|
+
@routing_table_purge_delay = routing_table_purge_delay
|
13
|
+
end
|
14
|
+
|
15
|
+
STALE_ROUTING_TABLE_PURGE_DELAY = 30.seconds
|
16
|
+
DEFAULT = new(1, 5.seconds, STALE_ROUTING_TABLE_PURGE_DELAY)
|
17
|
+
|
18
|
+
def with_routing_context(new_routing_context)
|
19
|
+
self.class.new(@max_routing_failures, @retry_timeout_delay, @routing_table_purge_delay, new_routing_context)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|