neo4j-ruby-driver 4.4.0.alpha.4 → 4.4.0.alpha.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/lib/neo4j/driver/exceptions/protocol_exception.rb +2 -2
  4. data/lib/neo4j/driver/internal/bolt_server_address.rb +6 -6
  5. data/lib/neo4j/driver/types/time.rb +4 -2
  6. data/ruby/neo4j/driver/config.rb +1 -1
  7. data/ruby/neo4j/driver/internal/async/inbound/inbound_message_dispatcher.rb +1 -1
  8. data/ruby/neo4j/driver/internal/async/network_connection.rb +15 -22
  9. data/ruby/neo4j/driver/internal/async/network_session.rb +4 -3
  10. data/ruby/neo4j/driver/internal/async/pool/channel.rb +1 -0
  11. data/ruby/neo4j/driver/internal/async/pool/{netty_channel_tracker.rb → channel_tracker.rb} +6 -8
  12. data/ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb +4 -3
  13. data/ruby/neo4j/driver/internal/cluster/cluster_composition.rb +10 -20
  14. data/ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb +2 -2
  15. data/ruby/neo4j/driver/internal/cluster/cluster_routing_table.rb +37 -54
  16. data/ruby/neo4j/driver/internal/cluster/identity_resolver.rb +1 -4
  17. data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb +6 -6
  18. data/ruby/neo4j/driver/internal/cluster/loadbalancing/load_balancer.rb +44 -80
  19. data/ruby/neo4j/driver/internal/cluster/multi_databases_routing_procedure_runner.rb +6 -9
  20. data/ruby/neo4j/driver/internal/cluster/rediscovery_impl.rb +65 -155
  21. data/ruby/neo4j/driver/internal/cluster/route_message_routing_procedure_runner.rb +2 -2
  22. data/ruby/neo4j/driver/internal/cluster/routing_procedure_cluster_composition_provider.rb +8 -12
  23. data/ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb +19 -3
  24. data/ruby/neo4j/driver/internal/cluster/routing_table_handler_impl.rb +46 -67
  25. data/ruby/neo4j/driver/internal/cluster/routing_table_registry_impl.rb +42 -61
  26. data/ruby/neo4j/driver/internal/cluster/single_database_routing_procedure_runner.rb +8 -10
  27. data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +2 -1
  28. data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +11 -14
  29. data/ruby/neo4j/driver/internal/database_name_util.rb +3 -3
  30. data/ruby/neo4j/driver/internal/default_bookmark_holder.rb +1 -7
  31. data/ruby/neo4j/driver/internal/direct_connection_provider.rb +1 -1
  32. data/ruby/neo4j/driver/internal/driver_factory.rb +4 -4
  33. data/ruby/neo4j/driver/internal/handlers/channel_releasing_reset_response_handler.rb +11 -10
  34. data/ruby/neo4j/driver/internal/handlers/legacy_pull_all_response_handler.rb +35 -25
  35. data/ruby/neo4j/driver/internal/handlers/pulln/auto_pull_response_handler.rb +1 -2
  36. data/ruby/neo4j/driver/internal/handlers/reset_response_handler.rb +1 -1
  37. data/ruby/neo4j/driver/internal/impersonation_util.rb +2 -2
  38. data/ruby/neo4j/driver/internal/internal_bookmark.rb +1 -1
  39. data/ruby/neo4j/driver/internal/internal_database_name.rb +3 -5
  40. data/ruby/neo4j/driver/internal/internal_driver.rb +1 -1
  41. data/ruby/neo4j/driver/internal/messaging/bolt_protocol_version.rb +3 -1
  42. data/ruby/neo4j/driver/internal/messaging/encode/route_message_encoder.rb +8 -2
  43. data/ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb +8 -13
  44. data/ruby/neo4j/driver/internal/messaging/request/begin_message.rb +2 -3
  45. data/ruby/neo4j/driver/internal/messaging/request/multi_database_util.rb +2 -2
  46. data/ruby/neo4j/driver/internal/messaging/request/route_message.rb +5 -10
  47. data/ruby/neo4j/driver/internal/messaging/request/run_with_metadata_message.rb +5 -3
  48. data/ruby/neo4j/driver/internal/messaging/request/transaction_metadata_builder.rb +2 -2
  49. data/ruby/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +1 -1
  50. data/ruby/neo4j/driver/internal/messaging/v44/message_writer_v44.rb +1 -1
  51. data/ruby/neo4j/driver/internal/read_only_bookmark_holder.rb +13 -0
  52. data/ruby/neo4j/driver/internal/resolved_bolt_server_address.rb +35 -0
  53. data/ruby/neo4j/driver/internal/security/security_plan_impl.rb +14 -9
  54. data/ruby/neo4j/driver/internal/util/error_util.rb +1 -1
  55. data/ruby/neo4j/driver/net/{server_address1.rb → server_address.rb} +2 -2
  56. data/ruby/neo4j/driver/query.rb +1 -1
  57. data/ruby/neo4j/driver/transaction_config.rb +5 -1
  58. data/ruby/neo4j/driver/values.rb +3 -3
  59. data/ruby/neo4j/driver/version.rb +1 -1
  60. metadata +11 -24
  61. data/ruby/neo4j/driver/internal/database_name.rb +0 -12
@@ -8,8 +8,6 @@ module Neo4j::Driver
8
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
9
  BOLT_SERVER_ADDRESSES_EMPTY_ARRAY = []
10
10
 
11
- attr_reader :routing_tables
12
-
13
11
  delegate :close, to: :@connection_pool
14
12
 
15
13
  def initialize(initial_router, settings, connection_pool, event_executor_group, logger, load_balancing_strategy, resolver, &domain_name_resolver)
@@ -23,106 +21,72 @@ module Neo4j::Driver
23
21
  end
24
22
 
25
23
  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, Async::ConnectionContext::PENDING_DATABASE_NAME_EXCEPTION_SUPPLIER),
30
- context.mode, context.impersonated_user, handler)
31
- end
32
- end
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)
33
28
  end
34
29
 
35
30
  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
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.'
45
35
  end
46
36
 
47
- def supports_multi_db?
48
- begin
49
- addresses = @rediscovery.resolve
50
- rescue StandardError => error
51
- return Util::Futures.failed_future(error)
52
- end
37
+ def routing_table_registry
38
+ @routing_tables
39
+ end
53
40
 
54
- result = Util::Futures.completed_with_null
41
+ def supports_multi_db?
42
+ addresses = @rediscovery.resolve
55
43
  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
44
+ addresses.lazy.map do |address|
45
+ private_suports_multi_db?(address)
46
+ rescue Exceptions::SecurityException
47
+ raise
48
+ rescue => error
49
+ Util::Futures.combine_errors(base_error, error)
50
+ end.find { |result| !result.nil? } or raise base_error
72
51
  end
73
52
 
74
53
  private
75
54
 
76
55
  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
56
+ conn = @connection_pool.acquire(address)
57
+ Messaging::Request::MultiDatabaseUtil.supports_multi_database?(conn)
58
+ ensure
59
+ conn&.release
81
60
  end
82
61
 
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
-
62
+ def acquire(mode, routing_table, attempt_errors = [])
89
63
  addresses = addresses_by_mode(mode, routing_table)
90
64
  address = select_address(mode, addresses)
91
65
 
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
66
+ unless address
67
+ error = Exceptions::SessionExpiredException.new(CONNECTION_ACQUISITION_COMPLETION_EXCEPTION_MESSAGE % [mode, routing_table])
68
+ attempt_errors.each(&error.method(:add_suppressed))
69
+ @log.error(CONNECTION_ACQUISITION_COMPLETION_FAILURE_MESSAGE)
70
+ @log.error(error)
71
+ raise error
99
72
  end
100
73
 
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
74
+ begin
75
+ @connection_pool.acquire(address)
76
+ rescue Exceptions::ServiceUnavailableException => error
77
+ @log.warn { CONNECTION_ACQUISITION_ATTEMPT_FAILURE_MESSAGE % address }
78
+ @log.debug(error)
79
+ attempt_errors << error
80
+ routing_table.forget(address)
81
+ acquire(mode, routing_table, attempt_errors)
118
82
  end
119
83
  end
120
84
 
121
85
  def addresses_by_mode(mode, routing_table)
122
86
  case mode
123
- when READ
87
+ when AccessMode::READ
124
88
  routing_table.readers
125
- when WRITE
89
+ when AccessMode::WRITE
126
90
  routing_table.writers
127
91
  else
128
92
  raise unknown_mode mode
@@ -131,9 +95,9 @@ module Neo4j::Driver
131
95
 
132
96
  def select_address(mode, addresses)
133
97
  case mode
134
- when READ
98
+ when AccessMode::READ
135
99
  @load_balancing_strategy.select_reader(addresses)
136
- when WRITE
100
+ when AccessMode::WRITE
137
101
  @load_balancing_strategy.select_writer(addresses)
138
102
  else
139
103
  raise unknown_mode mode
@@ -141,7 +105,7 @@ module Neo4j::Driver
141
105
  end
142
106
 
143
107
  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))
108
+ RoutingTableRegistryImpl.new(connection_pool, rediscovery, clock, logger, settings.routing_table_purge_delay)
145
109
  end
146
110
 
147
111
  def create_rediscovery(event_executor_group, initial_router, resolver, settings, clock, logger, domain_name_resolver)
@@ -5,13 +5,9 @@ module Neo4j::Driver
5
5
  # This implementation of the {@link RoutingProcedureRunner} works with multi database versions of Neo4j calling
6
6
  # the procedure `dbms.routing.getRoutingTable`
7
7
  class MultiDatabasesRoutingProcedureRunner < SingleDatabaseRoutingProcedureRunner
8
- DATABASE_NAME = 'database'
8
+ DATABASE_NAME = :database
9
9
  MULTI_DB_GET_ROUTING_TABLE = "CALL dbms.routing.getRoutingTable($%s, $%s)" % [SingleDatabaseRoutingProcedureRunner::ROUTING_CONTEXT, DATABASE_NAME]
10
10
 
11
- def initialize(context)
12
- super(context)
13
- end
14
-
15
11
  private
16
12
 
17
13
  def bookmark_holder(bookmark)
@@ -19,10 +15,11 @@ module Neo4j::Driver
19
15
  end
20
16
 
21
17
  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))
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)
26
23
  end
27
24
 
28
25
  def connection(connection)
@@ -24,59 +24,38 @@ module Neo4j::Driver
24
24
  # @param routingTable current routing table of the given database.
25
25
  # @param connectionPool connection pool.
26
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)
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
40
37
  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
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)
54
42
  end
55
- end
56
-
57
- result
58
43
  end
59
44
 
60
45
  def resolve
61
- resolved_addresses = java.util.LinkedList.new
62
46
  exception = nil
63
47
 
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
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 => e
52
+ exception&.add_suppressed(e)
53
+ exception ||= e
54
+ []
74
55
  end
75
56
 
76
57
  # 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
58
+ raise exception if resolved_addresses.empty? && exception
80
59
 
81
60
  resolved_addresses
82
61
  end
@@ -84,153 +63,84 @@ module Neo4j::Driver
84
63
  private
85
64
 
86
65
  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
66
+ if routing_table.prefer_initial_router
67
+ lookup_on_initial_router_then_on_known_routers(routing_table, connection_pool, bookmark, impersonated_user, base_error)
68
+ else
69
+ lookup_on_known_routers_then_on_initial_router(routing_table, connection_pool, bookmark, impersonated_user, base_error)
70
+ end
92
71
  end
93
72
 
94
73
  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
-
74
+ seen_servers = Set.new
75
+ lookup_on_known_routers(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error) ||
102
76
  lookup_on_initial_router(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
103
- end
104
77
  end
105
78
 
106
79
  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
80
+ lookup_on_initial_router(routing_table, connection_pool, Set.new, bookmark, impersonated_user, base_error) ||
81
+ lookup_on_known_routers(routing_table, connection_pool, Set.new, bookmark, impersonated_user, base_error)
116
82
  end
117
83
 
118
84
  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
85
+ routing_table.routers.lazy.map do |address|
86
+ lookup_on_router(address, true, routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
87
+ end.first&.then(&ClusterCompositionLookupResult.method(:new))
134
88
  end
135
89
 
136
90
  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
91
+ resolved_routers = resolve
92
+ (resolved_routers - seen_servers.to_a).lazy.filter_map do |address|
93
+ lookup_on_router(address, false, routing_table, connection_pool, nil, bookmark,
94
+ impersonated_user, base_error)
95
+ end.first&.then { |composition| ClusterCompositionLookupResult.new(composition, Set.new(resolved_routers)) }
161
96
  end
162
97
 
163
98
  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
99
+ address = resolve_address ? resolve_by_domain_name_or_throw_completion_exception(router_address, routing_table) : router_address
100
+ seen_servers&.send(:<<, address)
101
+ connection = connection_pool.acquire(address)
102
+ ImpersonationUtil.ensure_impersonation_support(connection, impersonated_user)
103
+ @provider.get_cluster_composition(connection, routing_table.database, bookmark, impersonated_user)
104
+ rescue => error
105
+ handle_routing_procedure_error(error, routing_table, router_address, base_error)
185
106
  end
186
107
 
187
108
  def handle_routing_procedure_error(error, routing_table, router_address, base_error)
188
- raise java.util.concurrent.CompletionException, error if must_abort_discovery(error)
109
+ raise error if must_abort_discovery(error)
189
110
 
190
111
  # Retriable error happened during discovery.
191
- discovery_error = Exceptions::DiscoveryException.new(RECOVERABLE_ROUTING_ERROR % router_address, error)
112
+ discovery_error = Exceptions::DiscoveryException.new(nil, RECOVERABLE_ROUTING_ERROR % router_address, error)
192
113
  Util::Futures.combine_errors(base_error, discovery_error) # we record each failure here
193
114
  warning_message = RECOVERABLE_DISCOVERY_ERROR_WITH_SERVER % router_address
194
115
  @log.warn(warning_message)
195
- @log.debug(warning_message, discovery_error)
116
+ @log.debug(discovery_error)
196
117
  routing_table.forget(router_address)
197
118
  nil
198
119
  end
199
120
 
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
121
+ def must_abort_discovery(error)
122
+ !error.is_a?(Exceptions::AuthorizationExpiredException) && error.is_a?(Exceptions::SecurityException) ||
123
+ error.is_a?(Exceptions::FatalDiscoveryException) ||
124
+ error.is_a?(Exceptions::IllegalStateException) &&
125
+ Spi::ConnectionPool::CONNECTION_POOL_CLOSED_ERROR_MESSAGE == error.message ||
126
+ error.is_a?(Exceptions::ClientException) &&
127
+ [INVALID_BOOKMARK_CODE, INVALID_BOOKMARK_MIXTURE_CODE].include?(error.code) ||
128
+ # Not sure why this is not im java
129
+ !error.is_a?(Exceptions::Neo4jException) ||
130
+ Util::ErrorUtil.fatal?(error)
217
131
  end
218
132
 
219
133
  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)
134
+ resolved_address = resolve_all_by_domain_name(address)
135
+ routing_table.replace_router_if_present(address, resolved_address)
223
136
 
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
137
+ resolved_address.unicast_stream.first or
138
+ raise Exceptions::IllegalStateException,
139
+ 'Unexpected condition, the ResolvedBoltServerAddress must always have at least one unicast address'
230
140
  end
231
141
 
232
142
  def resolve_all_by_domain_name(address)
233
- ResolvedBoltServerAddress.new(address.host, address.port, domain_name_resolver.resolve(address.host))
143
+ ResolvedBoltServerAddress.new(address.host, address.port, *@domain_name_resolver.call(address.host))
234
144
  end
235
145
  end
236
146
  end
@@ -16,9 +16,9 @@ module Neo4j::Driver
16
16
  Messaging::Request::RouteMessage.new(@routing_context, bookmark, database_name.database_name,
17
17
  impersonated_user),
18
18
  Handlers::RouteMessageResponseHandler.new(self))
19
- RoutingProcedureResponse.new(query(database_name), to_record(routing_table))
19
+ RoutingProcedureResponse.new(query(database_name), records: [to_record(@routing_table)])
20
20
  rescue => e
21
- RoutingProcedureResponse.new(query(database_name), e)
21
+ RoutingProcedureResponse.new(query(database_name), error: e)
22
22
  ensure
23
23
  direct_connection.release
24
24
  end
@@ -4,34 +4,30 @@ module Neo4j::Driver
4
4
  class RoutingProcedureClusterCompositionProvider
5
5
  PROTOCOL_ERROR_MESSAGE = "Failed to parse '%s' result received from server due to "
6
6
 
7
- def initialize(clock, routing_context)
8
- @clock = clock
7
+ def initialize(_clock, routing_context)
9
8
  @single_database_routing_procedure_runner = SingleDatabaseRoutingProcedureRunner.new(routing_context)
10
9
  @multi_database_routing_procedure_runner = MultiDatabasesRoutingProcedureRunner.new(routing_context)
11
10
  @route_message_routing_procedure_runner = RouteMessageRoutingProcedureRunner.new(routing_context)
12
11
  end
13
12
 
14
13
  def get_cluster_composition(connection, database_name, bookmark, impersonated_user)
15
- runner = if Messaging::Request::MultiDatabaseUtil.supports_route_message(connection)
14
+ runner = if Messaging::Request::MultiDatabaseUtil.supports_route_message?(connection)
16
15
  @route_message_routing_procedure_runner
17
- elsif Messaging::Request::MultiDatabaseUtil.supports_multi_database(connection)
16
+ elsif Messaging::Request::MultiDatabaseUtil.supports_multi_database?(connection)
18
17
  @multi_database_routing_procedure_runner
19
18
  else
20
19
  @single_database_routing_procedure_runner
21
20
  end
22
21
 
23
- runner.run(connection, database_name, bookmark, impersonated_user).then_apply do
24
- self::process_routing_response
25
- end
22
+ process_routing_response(runner.run(connection, database_name, bookmark, impersonated_user))
26
23
  end
27
24
 
28
25
  def process_routing_response(response)
29
- if !response.success?
30
- raise java.util.concurrent.CompletionException, "Failed to run '#{invoked_procedure_string(response)}' on server. Please make sure that there is a Neo4j server or cluster up running.", response.error
26
+ unless response.success?
27
+ raise response.error.class, "Failed to run '#{invoked_procedure_string(response)}' on server. Please make sure that there is a Neo4j server or cluster up running."
31
28
  end
32
29
 
33
30
  records = response.records
34
- now = clock.millis
35
31
 
36
32
  # the record size is wrong
37
33
  if records.size != 1
@@ -40,7 +36,7 @@ module Neo4j::Driver
40
36
 
41
37
  # failed to parse the record
42
38
  begin
43
- cluster = ClusterComposition.parse( records[0], now)
39
+ cluster = ClusterComposition.parse( records[0], Time.now)
44
40
  rescue Exceptions::Value::ValueException => e
45
41
  raise Exceptions::ProtocolException, "#{PROTOCOL_ERROR_MESSAGE % invoked_procedure_string(response)} unparsable record received. #{e}"
46
42
  end
@@ -56,7 +52,7 @@ module Neo4j::Driver
56
52
 
57
53
  def invoked_procedure_string(response)
58
54
  query = response.procedure
59
- query.text + '' + query.parameters
55
+ "#{query.text} #{query.parameters}"
60
56
  end
61
57
  end
62
58
  end
@@ -2,16 +2,32 @@ module Neo4j::Driver
2
2
  module Internal
3
3
  module Cluster
4
4
  class RoutingProcedureResponse
5
- attr_reader :procedure, :records, :error
5
+ attr_reader :procedure
6
6
 
7
- def initialize(procedure, records = nil, error = nil)
7
+ def initialize(procedure, records: nil, error: nil)
8
8
  @procedure = procedure
9
9
  @records = records
10
10
  @error = error
11
11
  end
12
12
 
13
13
  def success?
14
- !records.nil?
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
15
31
  end
16
32
  end
17
33
  end