neo4j-ruby-driver 4.4.0.alpha.5 → 4.4.0.alpha.8

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/lib/neo4j/driver/exceptions/protocol_exception.rb +2 -2
  3. data/lib/neo4j/driver/internal/bolt_server_address.rb +6 -6
  4. data/lib/neo4j/driver/types/time.rb +4 -2
  5. data/ruby/neo4j/driver/config.rb +1 -1
  6. data/ruby/neo4j/driver/graph_database.rb +2 -2
  7. data/ruby/neo4j/driver/internal/async/inbound/inbound_message_dispatcher.rb +2 -3
  8. data/ruby/neo4j/driver/internal/async/network_session.rb +4 -3
  9. data/ruby/neo4j/driver/internal/async/pool/{netty_channel_tracker.rb → channel_tracker.rb} +6 -8
  10. data/ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb +3 -3
  11. data/ruby/neo4j/driver/internal/async/unmanaged_transaction.rb +18 -20
  12. data/ruby/neo4j/driver/internal/cluster/cluster_composition.rb +10 -20
  13. data/ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb +2 -2
  14. data/ruby/neo4j/driver/internal/cluster/cluster_routing_table.rb +38 -55
  15. data/ruby/neo4j/driver/internal/cluster/identity_resolver.rb +1 -4
  16. data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb +6 -6
  17. data/ruby/neo4j/driver/internal/cluster/loadbalancing/load_balancer.rb +44 -80
  18. data/ruby/neo4j/driver/internal/cluster/multi_databases_routing_procedure_runner.rb +6 -9
  19. data/ruby/neo4j/driver/internal/cluster/rediscovery_impl.rb +65 -155
  20. data/ruby/neo4j/driver/internal/cluster/route_message_routing_procedure_runner.rb +2 -2
  21. data/ruby/neo4j/driver/internal/cluster/routing_procedure_cluster_composition_provider.rb +8 -12
  22. data/ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb +19 -3
  23. data/ruby/neo4j/driver/internal/cluster/routing_table_handler_impl.rb +46 -67
  24. data/ruby/neo4j/driver/internal/cluster/routing_table_registry_impl.rb +42 -61
  25. data/ruby/neo4j/driver/internal/cluster/single_database_routing_procedure_runner.rb +15 -19
  26. data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +31 -19
  27. data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +12 -15
  28. data/ruby/neo4j/driver/internal/database_name_util.rb +3 -3
  29. data/ruby/neo4j/driver/internal/default_bookmark_holder.rb +1 -7
  30. data/ruby/neo4j/driver/internal/direct_connection_provider.rb +1 -1
  31. data/ruby/neo4j/driver/internal/driver_factory.rb +4 -4
  32. data/ruby/neo4j/driver/internal/handlers/commit_tx_response_handler.rb +4 -4
  33. data/ruby/neo4j/driver/internal/handlers/legacy_pull_all_response_handler.rb +90 -51
  34. data/ruby/neo4j/driver/internal/handlers/pulln/auto_pull_response_handler.rb +33 -44
  35. data/ruby/neo4j/driver/internal/handlers/rollback_tx_response_handler.rb +7 -1
  36. data/ruby/neo4j/driver/internal/impersonation_util.rb +2 -2
  37. data/ruby/neo4j/driver/internal/internal_bookmark.rb +1 -1
  38. data/ruby/neo4j/driver/internal/internal_database_name.rb +3 -5
  39. data/ruby/neo4j/driver/internal/internal_result.rb +5 -5
  40. data/ruby/neo4j/driver/internal/internal_session.rb +1 -1
  41. data/ruby/neo4j/driver/internal/internal_transaction.rb +4 -4
  42. data/ruby/neo4j/driver/internal/messaging/bolt_protocol_version.rb +3 -1
  43. data/ruby/neo4j/driver/internal/messaging/encode/route_message_encoder.rb +8 -2
  44. data/ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb +8 -13
  45. data/ruby/neo4j/driver/internal/messaging/request/abstract_streaming_message.rb +4 -1
  46. data/ruby/neo4j/driver/internal/messaging/request/begin_message.rb +2 -3
  47. data/ruby/neo4j/driver/internal/messaging/request/multi_database_util.rb +2 -2
  48. data/ruby/neo4j/driver/internal/messaging/request/route_message.rb +5 -10
  49. data/ruby/neo4j/driver/internal/messaging/request/run_with_metadata_message.rb +5 -3
  50. data/ruby/neo4j/driver/internal/messaging/request/transaction_metadata_builder.rb +2 -2
  51. data/ruby/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +8 -4
  52. data/ruby/neo4j/driver/internal/messaging/v44/message_writer_v44.rb +1 -1
  53. data/ruby/neo4j/driver/internal/read_only_bookmark_holder.rb +13 -0
  54. data/ruby/neo4j/driver/internal/resolved_bolt_server_address.rb +35 -0
  55. data/ruby/neo4j/driver/internal/security/security_plan_impl.rb +14 -9
  56. data/ruby/neo4j/driver/internal/util/error_util.rb +1 -1
  57. data/ruby/neo4j/driver/internal/util/result_holder.rb +70 -0
  58. data/ruby/neo4j/driver/net/{server_address1.rb → server_address.rb} +2 -2
  59. data/ruby/neo4j/driver/query.rb +1 -1
  60. data/ruby/neo4j/driver/transaction_config.rb +5 -1
  61. data/ruby/neo4j/driver/values.rb +3 -3
  62. data/ruby/neo4j/driver/version.rb +1 -1
  63. metadata +16 -14
  64. 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