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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) 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/internal/async/network_session.rb +4 -3
  6. data/ruby/neo4j/driver/internal/async/pool/{netty_channel_tracker.rb → channel_tracker.rb} +6 -8
  7. data/ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb +3 -3
  8. data/ruby/neo4j/driver/internal/cluster/cluster_composition.rb +10 -20
  9. data/ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb +2 -2
  10. data/ruby/neo4j/driver/internal/cluster/cluster_routing_table.rb +37 -54
  11. data/ruby/neo4j/driver/internal/cluster/identity_resolver.rb +1 -4
  12. data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb +6 -6
  13. data/ruby/neo4j/driver/internal/cluster/loadbalancing/load_balancer.rb +44 -80
  14. data/ruby/neo4j/driver/internal/cluster/multi_databases_routing_procedure_runner.rb +6 -9
  15. data/ruby/neo4j/driver/internal/cluster/rediscovery_impl.rb +65 -155
  16. data/ruby/neo4j/driver/internal/cluster/route_message_routing_procedure_runner.rb +2 -2
  17. data/ruby/neo4j/driver/internal/cluster/routing_procedure_cluster_composition_provider.rb +8 -12
  18. data/ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb +19 -3
  19. data/ruby/neo4j/driver/internal/cluster/routing_table_handler_impl.rb +46 -67
  20. data/ruby/neo4j/driver/internal/cluster/routing_table_registry_impl.rb +42 -61
  21. data/ruby/neo4j/driver/internal/cluster/single_database_routing_procedure_runner.rb +8 -10
  22. data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +2 -1
  23. data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +11 -14
  24. data/ruby/neo4j/driver/internal/database_name_util.rb +3 -3
  25. data/ruby/neo4j/driver/internal/default_bookmark_holder.rb +1 -7
  26. data/ruby/neo4j/driver/internal/direct_connection_provider.rb +1 -1
  27. data/ruby/neo4j/driver/internal/driver_factory.rb +4 -4
  28. data/ruby/neo4j/driver/internal/handlers/legacy_pull_all_response_handler.rb +34 -24
  29. data/ruby/neo4j/driver/internal/impersonation_util.rb +2 -2
  30. data/ruby/neo4j/driver/internal/internal_bookmark.rb +1 -1
  31. data/ruby/neo4j/driver/internal/internal_database_name.rb +3 -5
  32. data/ruby/neo4j/driver/internal/messaging/bolt_protocol_version.rb +3 -1
  33. data/ruby/neo4j/driver/internal/messaging/encode/route_message_encoder.rb +8 -2
  34. data/ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb +8 -13
  35. data/ruby/neo4j/driver/internal/messaging/request/begin_message.rb +2 -3
  36. data/ruby/neo4j/driver/internal/messaging/request/multi_database_util.rb +2 -2
  37. data/ruby/neo4j/driver/internal/messaging/request/route_message.rb +5 -10
  38. data/ruby/neo4j/driver/internal/messaging/request/run_with_metadata_message.rb +5 -3
  39. data/ruby/neo4j/driver/internal/messaging/request/transaction_metadata_builder.rb +2 -2
  40. data/ruby/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +1 -1
  41. data/ruby/neo4j/driver/internal/messaging/v44/message_writer_v44.rb +1 -1
  42. data/ruby/neo4j/driver/internal/read_only_bookmark_holder.rb +13 -0
  43. data/ruby/neo4j/driver/internal/resolved_bolt_server_address.rb +35 -0
  44. data/ruby/neo4j/driver/internal/security/security_plan_impl.rb +14 -9
  45. data/ruby/neo4j/driver/internal/util/error_util.rb +1 -1
  46. data/ruby/neo4j/driver/net/{server_address1.rb → server_address.rb} +2 -2
  47. data/ruby/neo4j/driver/query.rb +1 -1
  48. data/ruby/neo4j/driver/transaction_config.rb +5 -1
  49. data/ruby/neo4j/driver/values.rb +3 -3
  50. data/ruby/neo4j/driver/version.rb +1 -1
  51. metadata +6 -5
  52. data/ruby/neo4j/driver/internal/database_name.rb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1dc1f5cbdb0085a5e75fd3809b9e830c5c60e93f688e42c939c2fbe7015bde7
4
- data.tar.gz: 81786afebfdb15a41550bf5997aef82adcb26ea8f5551a1e48e8c7571211e994
3
+ metadata.gz: a035a8385e54c70c851003ce4131072610617d515f118d2d4b03f6ada71de3a7
4
+ data.tar.gz: bc8dfddb76165d4aea25d702e1d4bb1be5db3bb375d25f48fab39acb7f247c07
5
5
  SHA512:
6
- metadata.gz: 0ba9e1ff39437d069150c3d7706a93c7b21054d2fb5e03ecc1bdc2cd864145bd2609cfca46448b0a84354f78ab983164b25bdcc12e8fb8b6061eea498c4651c3
7
- data.tar.gz: 3549a85e58efeb737c6d48cde04ce8da6bd2e2d07d2b927ff8669a4a9fca390f621e60e7e6670d286b66cb242aff625b1112760e8470632a8f6a89464bae4c20
6
+ metadata.gz: 17a1b5ada9f09120e7dda4316504d59fedf366696d27c26e87c5feeee381a876409a75eaa05cbc177af64415946af7ec8c1de7b4ed5e637ffc464a40c1fd4eea
7
+ data.tar.gz: aa41d20c4794dac6841aa1bf70cb0c3e8573a658e74d8aa4e475f45a2a0a9072056633a83f8744251014ab5a805b6ec368f4a75b036316c2179bc1bcc1f8f8fa
@@ -8,8 +8,8 @@ module Neo4j
8
8
  class ProtocolException < Neo4jException
9
9
  CODE = "Protocol violation: "
10
10
 
11
- def initialize(message, e)
12
- super("#{CODE}message", e)
11
+ def initialize(message, e = nil)
12
+ super(nil, "#{CODE}#{message}", e)
13
13
  end
14
14
  end
15
15
  end
@@ -67,13 +67,15 @@ module Neo4j::Driver
67
67
  LOCAL_DEFAULT = new(host: 'localhost', port: DEFAULT_PORT)
68
68
 
69
69
  def self.from(address)
70
- address.is_a?(BoltServerAddress) ? address : new(address.host, address.port)
70
+ address.is_a?(BoltServerAddress) ? address : new(host: address.host, port: address.port)
71
71
  end
72
72
 
73
- def eql?(other)
74
- attributes.eql?(other&.attributes)
73
+ def ==(other)
74
+ attributes == other&.attributes
75
75
  end
76
76
 
77
+ alias eql? ==
78
+
77
79
  def to_s
78
80
  "#{host}#{"(#{connection_host})" unless host == connection_host}:#{port}"
79
81
  end
@@ -84,11 +86,9 @@ module Neo4j::Driver
84
86
 
85
87
  # @return stream of unicast addresses.
86
88
  def unicast_stream
87
- [self]
89
+ Set[self]
88
90
  end
89
91
 
90
- private
91
-
92
92
  def attributes
93
93
  [@host, @connection_host, @port]
94
94
  end
@@ -30,10 +30,12 @@ module Neo4j
30
30
  end
31
31
  end
32
32
 
33
- def eql?(other)
34
- other.is_a?(self.class) && self.class.significant_fields.all? { |elem| send(elem).eql?(other.send(elem)) }
33
+ def ==(other)
34
+ other.is_a?(self.class) && self.class.significant_fields.all? { |elem| send(elem) == other.send(elem) }
35
35
  end
36
36
 
37
+ alias eql? ==
38
+
37
39
  def +(numeric)
38
40
  self.class.new(@time + numeric)
39
41
  end
@@ -10,8 +10,8 @@ module Neo4j::Driver
10
10
  @retry_logic = retry_logic
11
11
  @log = Logging::PrefixedLogger.new("[#{hash}]", logger)
12
12
  @bookmark_holder = bookmark_holder
13
- @database_name = database_name.database_name
14
- @connection_context = NetworkSessionConnectionContext.new(@database_name, @bookmark_holder.bookmark, impersonated_user)
13
+ # @database_name = database_name.database_name
14
+ @connection_context = NetworkSessionConnectionContext.new(database_name, @bookmark_holder.bookmark, impersonated_user)
15
15
  @fetch_size = fetch_size
16
16
  @open = Concurrent::AtomicBoolean.new(true)
17
17
  end
@@ -133,7 +133,8 @@ module Neo4j::Driver
133
133
  # This bookmark is only used for rediscovery.
134
134
  # It has to be the initial bookmark given at the creation of the session.
135
135
  # As only that bookmark could carry extra system bookmarks
136
- attr_reader :database_name, :mode, :rediscovery_bookmark, :impersonated_user
136
+ attr_accessor :database_name
137
+ attr :mode, :rediscovery_bookmark, :impersonated_user
137
138
 
138
139
  def initialize(database_name, bookmark, impersonated_user)
139
140
  @database_name = database_name
@@ -2,22 +2,20 @@ module Neo4j::Driver
2
2
  module Internal
3
3
  module Async
4
4
  module Pool
5
- class NettyChannelTracker
5
+ class ChannelTracker
6
6
  attr_reader :lock, :read, :write, :address_to_in_use_channel_count, :address_to_idle_channel_count, :log,
7
7
  :metrics_listener, :close_listener, :all_channels
8
8
 
9
- def initialize(metrics_listener, logger, options = {},event_executor = nil, channels = nil)
9
+ def initialize(metrics_listener, logger, **options)
10
10
  @metrics_listener = metrics_listener
11
11
  @log = logger
12
- @all_channels = options[:channels] ? channels : Java::IoNettyChannelGroup::DefaultChannelGroup.new("all-connections", options[:event_executor])
13
- @lock = java.util.concurrent.locks.ReentrantReadWriteLock.new
14
- @read = lock.read_lock
15
- @write = lock.write_lock
16
- @close_listener = -> (future) { channel_closed(future.channel) }
12
+ @all_channels = options[:channels]
13
+ @lock = Concurrent::ReentrantReadWriteLock.new
14
+ @close_listener = method(:channel_closed)
17
15
  end
18
16
 
19
17
  def channel_released(channel)
20
- do_in_write_lock do
18
+ @lock.with_write_lock do
21
19
  decrement_in_use(channel)
22
20
  increment_idle(channel)
23
21
  channel.close_future.add_listener(close_listener)
@@ -32,8 +32,7 @@ module Neo4j::Driver
32
32
  @address_to_pool_lock.with_write_lock do
33
33
  @address_to_pool.each do |address, pool|
34
34
  unless addresses_to_retain.include?(address)
35
- active_channels = @netty_channel_tracker.in_use_channel_count(address)
36
- if active_channels.zero?
35
+ unless pool.busy?
37
36
  # address is not present in updated routing table and has no active connections
38
37
  # it's now safe to terminate corresponding connection pool and forget about it
39
38
  @address_to_pool.delete(address)
@@ -48,7 +47,8 @@ module Neo4j::Driver
48
47
  end
49
48
 
50
49
  def in_use_connections(address)
51
- @netty_channel_tracker.in_use_channel_count(address)
50
+ @address_to_pool[address]&.size || 0
51
+ # @netty_channel_tracker.in_use_channel_count(address)
52
52
  end
53
53
 
54
54
  def idle_connections(address)
@@ -2,45 +2,35 @@ module Neo4j::Driver
2
2
  module Internal
3
3
  module Cluster
4
4
  class ClusterComposition < Struct.new(:expiration_timestamp, :readers, :writers, :routers, :database_name)
5
- private
6
-
7
- MAX_LONG = 2 ^ 63 - 1
8
- MAX_TTL = MAX_LONG / 1000
9
-
10
- public
11
-
12
5
  def initialize(expiration_timestamp:, database_name:, readers: [], writers: [], routers: [])
13
6
  super(expiration_timestamp, readers, writers, routers, database_name)
14
7
  end
15
8
 
16
9
  def has_writers?
17
- @writers.present?
10
+ writers.present?
18
11
  end
19
12
 
20
13
  def has_routers_and_readers?
21
- @routers.present? && @readers.present?
14
+ routers.present? && readers.present?
22
15
  end
23
16
 
24
17
  def self.parse(record, now)
25
- return if record.nil?
26
- new(expiration_timestamp: expiration_timestamp(now, record), database_name: record['db'],
27
- **record['servers'].to_h { |value| [servers(value['role']), BoltServerAddress.new(value['addresses'])] })
18
+ return unless record
19
+ new(expiration_timestamp: expiration_timestamp(now, record), database_name: record[:db],
20
+ **record[:servers].to_h do |value|
21
+ [servers(value[:role]),
22
+ value[:addresses].map { |address| BoltServerAddress.new(uri: BoltServerAddress.uri_from(address)) }]
23
+ end)
28
24
  end
29
25
 
30
26
  private
31
27
 
32
28
  def self.expiration_timestamp(now, record)
33
29
  ttl = record['ttl']
34
- expiration_timestamp = now + ttl * 1000
35
-
36
- if ttl < 0 || ttl >= MAX_TTL || expiration_timestamp < 0
37
- expiration_timestamp = MAX_LONG
38
- end
39
-
40
- expiration_timestamp
30
+ now + (ttl.negative? ? 1000.years : ttl.seconds)
41
31
  end
42
32
 
43
- def servers(role)
33
+ def self.servers(role)
44
34
  case role
45
35
  when 'READ'
46
36
  :readers
@@ -2,10 +2,10 @@ module Neo4j::Driver
2
2
  module Internal
3
3
  module Cluster
4
4
  class ClusterCompositionLookupResult
5
- attr_reader :composition, :resolved_initial_routers
5
+ attr_reader :cluster_composition, :resolved_initial_routers
6
6
 
7
7
  def initialize(composition, resolved_initial_routers = nil)
8
- @composition = composition
8
+ @cluster_composition = composition
9
9
  @resolved_initial_routers = resolved_initial_routers
10
10
  end
11
11
  end
@@ -4,39 +4,32 @@ module Neo4j::Driver
4
4
  class ClusterRoutingTable
5
5
  MIN_ROUTERS = 1
6
6
 
7
- attr_reader :database_name
8
-
9
- def initialize(of_database, clock, routing_addresses)
7
+ def initialize(of_database, _clock, *routing_addresses)
10
8
  @database_name = of_database
11
- @clock = clock
12
- @expiration_timestamp = clock.millis - 1
13
- @routers = routing_addresses.freeze
14
- @table_lock = java.util.concurrent.locks.ReentrantReadWriteLock.new
9
+ @expiration_timestamp = Time.now
10
+ @routers = routing_addresses.to_set.freeze
11
+ @table_lock = Concurrent::ReentrantReadWriteLock.new
15
12
  @prefer_initial_router = true
16
- @disused = {}
17
- @readers = []
18
- @writers = []
13
+ @disused = Set.new
14
+ @readers = Set.new
15
+ @writers = Set.new
19
16
  end
20
17
 
21
18
  def stale_for?(mode)
22
- Util::LockUtil.execute_with_lock(@table_lock.read_lock) do
23
- @expiration_timestamp < @clock.millis ||
24
- routers.size < MIN_ROUTERS ||
25
- (mode == AccessMode::READ && @readers.size == 0) ||
26
- (mode == AccessMode::WRITE && @writers.size == 0)
19
+ @table_lock.with_read_lock do
20
+ @expiration_timestamp <= Time.now ||
21
+ routers.size < MIN_ROUTERS ||
22
+ (mode == AccessMode::READ && @readers.size == 0) ||
23
+ (mode == AccessMode::WRITE && @writers.size == 0)
27
24
  end
28
25
  end
29
26
 
30
27
  def has_been_stale_for?(extra_time)
31
- total_time = Util::LockUtil.execute_with_lock(@table_lock.read_lock, -> () { @expiration_timestamp }) + extra_time
32
-
33
- total_time = java.lang.Long::MAX_VALUE if total_time < 0
34
-
35
- total_time < @clock.millis
28
+ Time.now - @table_lock.with_read_lock { @expiration_timestamp } >= extra_time
36
29
  end
37
30
 
38
31
  def update(cluster)
39
- Util::LockUtil.execute_with_lock(@table_lock.write_lock) do
32
+ @table_lock.with_write_lock do
40
33
  @expiration_timestamp = cluster.expiration_timestamp
41
34
  @readers = new_with_reused_addresses(@readers, @disused, cluster.readers)
42
35
  @writers = new_with_reused_addresses(@writers, @disused, cluster.writers)
@@ -47,7 +40,7 @@ module Neo4j::Driver
47
40
  end
48
41
 
49
42
  def forget(address)
50
- Util::LockUtil.execute_with_lock(@table_lock.write_lock) do
43
+ @table_lock.with_write_lock do
51
44
  @routers = new_without_address_if_present(@routers, address)
52
45
  @readers = new_without_address_if_present(@readers, address)
53
46
  @writers = new_without_address_if_present(@writers, address)
@@ -56,27 +49,27 @@ module Neo4j::Driver
56
49
  end
57
50
 
58
51
  def readers
59
- Util::LockUtil.execute_with_lock(@table_lock.read_lock, -> () { @readers })
52
+ @table_lock.with_read_lock { @readers }
60
53
  end
61
54
 
62
55
  def writers
63
- Util::LockUtil.execute_with_lock(@table_lock.read_lock, -> () { @writers })
56
+ @table_lock.with_read_lock { @writers }
64
57
  end
65
58
 
66
59
  def routers
67
- Util::LockUtil.execute_with_lock(@table_lock.read_lock, -> () { @routers })
60
+ @table_lock.with_read_lock { @routers }
68
61
  end
69
62
 
70
63
  def servers
71
- Util::LockUtil.execute_with_lock(@table_lock.write_lock) do
72
- servers = []
73
- servers << (@readers)
74
- servers << (@writers)
75
- servers << (@routers)
76
- servers << (@disused)
64
+ @table_lock.with_write_lock do
65
+ [@readers, @writers, @routers, @disused].reduce(&:+)
77
66
  end
78
67
  end
79
68
 
69
+ def database
70
+ @database_name
71
+ end
72
+
80
73
  def forget_writer(to_remove)
81
74
  Util::LockUtil.execute_with_lock(@table_lock.write_lock) do
82
75
  @writers = new_without_address_if_present(@writers, to_remove)
@@ -85,53 +78,43 @@ module Neo4j::Driver
85
78
  end
86
79
 
87
80
  def replace_router_if_present(old_router, new_router)
88
- Util::LockUtil.execute_with_lock(@table_lock.write_lock, -> () { @routers = new_with_address_replaced_if_present(@routers, old_router, new_router) } )
81
+ @table_lock.with_write_lock { @routers = new_with_address_replaced_if_present(@routers, old_router, new_router) }
89
82
  end
90
83
 
91
84
  def prefer_initial_router
92
- Util::LockUtil.execute_with_lock(@table_lock.read_lock, -> () { @prefer_initial_router })
85
+ @table_lock.with_read_lock { @prefer_initial_router }
93
86
  end
94
87
 
95
88
  def expiration_timestamp
96
- Util::LockUtil.execute_with_lock(@table_lock.read_lock, -> () { @expiration_timestamp })
89
+ @table_lock.with_read_lock { @expiration_timestamp }
97
90
  end
98
91
 
99
92
  def to_s
100
- Util::LockUtil.execute_with_lock(@table_lock.read_lock) do
101
- "Ttl #{@expiration_timestamp}, currentTime #{@clock.millis}, routers #{@routers}, writers #{@writers}, readers #{@readers}, database '#{database_name.description}'"
93
+ @table_lock.with_read_lock do
94
+ "Ttl #{@expiration_timestamp}, currentTime #{Time.now}, routers #{@routers}, writers #{@writers}, readers #{@readers}, database '#{@database_name.description}'"
102
95
  end
103
96
  end
104
97
 
105
98
  private
106
99
 
107
100
  def new_without_address_if_present(addresses, address_to_skip)
108
- new_list = []
109
-
110
- addresses.each do |address|
111
- new_list << address unless address.eql?(address_to_skip)
112
- end
113
-
114
- new_list.freeze
101
+ (addresses - [address_to_skip]).freeze
115
102
  end
116
103
 
117
104
  def new_with_address_replaced_if_present(addresses, old_address, new_address)
118
- new_list = []
119
-
120
- addresses.each { |address| new_list << address.eql?(old_address) ? new_address : address }
121
-
122
- new_list.freeze
105
+ addresses.map { |address| address == old_address ? new_address : address }.freeze
123
106
  end
124
107
 
125
108
  def new_with_reused_addresses(current_addresses, disused_addresses, new_addresses)
126
- new_list = java.util.stream.Stream.concat(current_addresses.stream, disused_addresses.stream)
127
- .filter(-> (address) { new_addresses.remove(to_bolt_server_address(address)) })
128
- .collect(java.util.stream.Collectors.to_collection(-> () { Array.new(new_addresses.size) }))
129
- new_list << new_addresses
130
- new_list.freeze
109
+ (current_addresses + disused_addresses + new_addresses).freeze
131
110
  end
132
111
 
133
112
  def to_bolt_server_address(address)
134
- BoltServerAddress.class.eql?(address.class) ? address : BoltServerAddress.new(address.host, address.port)
113
+ if BoltServerAddress.class == address.class
114
+ address
115
+ else
116
+ BoltServerAddress.new(host: address.host, port: address.port)
117
+ end
135
118
  end
136
119
  end
137
120
  end
@@ -3,10 +3,7 @@ module Neo4j::Driver
3
3
  module Cluster
4
4
  class IdentityResolver
5
5
  IDENTITY_RESOLVER = new
6
-
7
- def resolve(initial_router)
8
- java.util.Collections.singleton(initial_router)
9
- end
6
+ alias resolve Array
10
7
  end
11
8
  end
12
9
  end
@@ -28,10 +28,9 @@ module Neo4j::Driver
28
28
 
29
29
  def select(addresses, addresses_index, address_type)
30
30
  size = addresses.size
31
-
32
31
  if size == 0
33
32
  @log.debug("Unable to select #{address_type}, no known addresses given")
34
- return nil
33
+ return
35
34
  end
36
35
 
37
36
  # choose start index for iteration in round-robin fashion
@@ -39,22 +38,23 @@ module Neo4j::Driver
39
38
  index = start_index
40
39
 
41
40
  least_connected_address = nil
42
- least_active_connections = java.lang.Integer::MAX_VALUE
41
+ least_active_connections = nil
43
42
 
44
43
  # iterate over the array to find the least connected address
44
+ addresses = addresses.to_a
45
45
  loop do
46
46
  address = addresses[index]
47
47
  active_connections = @connection_pool.in_use_connections(address)
48
48
 
49
- if active_connections < least_active_connections
49
+ if least_active_connections.nil? || active_connections < least_active_connections
50
50
  least_connected_address = address
51
51
  least_active_connections = active_connections
52
52
  end
53
53
 
54
54
  # loop over to the start of the array when end is reached
55
- index = (index == size - 1) ? 0 : index += 1
55
+ index = (index + 1) % size
56
56
 
57
- break if index != start_index
57
+ break if index == start_index
58
58
  end
59
59
 
60
60
  @log.debug("Selected #{address_type} with address: '#{least_connected_address}' and active connections: #{least_active_connections}")
@@ -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)