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

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 (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)