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.
- checksums.yaml +4 -4
- data/lib/neo4j/driver/exceptions/protocol_exception.rb +2 -2
- data/lib/neo4j/driver/internal/bolt_server_address.rb +6 -6
- data/lib/neo4j/driver/types/time.rb +4 -2
- data/ruby/neo4j/driver/internal/async/network_session.rb +4 -3
- data/ruby/neo4j/driver/internal/async/pool/{netty_channel_tracker.rb → channel_tracker.rb} +6 -8
- data/ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb +3 -3
- data/ruby/neo4j/driver/internal/cluster/cluster_composition.rb +10 -20
- data/ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb +2 -2
- data/ruby/neo4j/driver/internal/cluster/cluster_routing_table.rb +37 -54
- data/ruby/neo4j/driver/internal/cluster/identity_resolver.rb +1 -4
- data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb +6 -6
- data/ruby/neo4j/driver/internal/cluster/loadbalancing/load_balancer.rb +44 -80
- data/ruby/neo4j/driver/internal/cluster/multi_databases_routing_procedure_runner.rb +6 -9
- data/ruby/neo4j/driver/internal/cluster/rediscovery_impl.rb +65 -155
- data/ruby/neo4j/driver/internal/cluster/route_message_routing_procedure_runner.rb +2 -2
- data/ruby/neo4j/driver/internal/cluster/routing_procedure_cluster_composition_provider.rb +8 -12
- data/ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb +19 -3
- data/ruby/neo4j/driver/internal/cluster/routing_table_handler_impl.rb +46 -67
- data/ruby/neo4j/driver/internal/cluster/routing_table_registry_impl.rb +42 -61
- data/ruby/neo4j/driver/internal/cluster/single_database_routing_procedure_runner.rb +8 -10
- data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +2 -1
- data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +11 -14
- data/ruby/neo4j/driver/internal/database_name_util.rb +3 -3
- data/ruby/neo4j/driver/internal/default_bookmark_holder.rb +1 -7
- data/ruby/neo4j/driver/internal/direct_connection_provider.rb +1 -1
- data/ruby/neo4j/driver/internal/driver_factory.rb +4 -4
- data/ruby/neo4j/driver/internal/handlers/legacy_pull_all_response_handler.rb +34 -24
- data/ruby/neo4j/driver/internal/impersonation_util.rb +2 -2
- data/ruby/neo4j/driver/internal/internal_bookmark.rb +1 -1
- data/ruby/neo4j/driver/internal/internal_database_name.rb +3 -5
- data/ruby/neo4j/driver/internal/messaging/bolt_protocol_version.rb +3 -1
- data/ruby/neo4j/driver/internal/messaging/encode/route_message_encoder.rb +8 -2
- data/ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb +8 -13
- data/ruby/neo4j/driver/internal/messaging/request/begin_message.rb +2 -3
- data/ruby/neo4j/driver/internal/messaging/request/multi_database_util.rb +2 -2
- data/ruby/neo4j/driver/internal/messaging/request/route_message.rb +5 -10
- data/ruby/neo4j/driver/internal/messaging/request/run_with_metadata_message.rb +5 -3
- data/ruby/neo4j/driver/internal/messaging/request/transaction_metadata_builder.rb +2 -2
- data/ruby/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +1 -1
- data/ruby/neo4j/driver/internal/messaging/v44/message_writer_v44.rb +1 -1
- data/ruby/neo4j/driver/internal/read_only_bookmark_holder.rb +13 -0
- data/ruby/neo4j/driver/internal/resolved_bolt_server_address.rb +35 -0
- data/ruby/neo4j/driver/internal/security/security_plan_impl.rb +14 -9
- data/ruby/neo4j/driver/internal/util/error_util.rb +1 -1
- data/ruby/neo4j/driver/net/{server_address1.rb → server_address.rb} +2 -2
- data/ruby/neo4j/driver/query.rb +1 -1
- data/ruby/neo4j/driver/transaction_config.rb +5 -1
- data/ruby/neo4j/driver/values.rb +3 -3
- data/ruby/neo4j/driver/version.rb +1 -1
- metadata +6 -5
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a035a8385e54c70c851003ce4131072610617d515f118d2d4b03f6ada71de3a7
|
4
|
+
data.tar.gz: bc8dfddb76165d4aea25d702e1d4bb1be5db3bb375d25f48fab39acb7f247c07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17a1b5ada9f09120e7dda4316504d59fedf366696d27c26e87c5feeee381a876409a75eaa05cbc177af64415946af7ec8c1de7b4ed5e637ffc464a40c1fd4eea
|
7
|
+
data.tar.gz: aa41d20c4794dac6841aa1bf70cb0c3e8573a658e74d8aa4e475f45a2a0a9072056633a83f8744251014ab5a805b6ec368f4a75b036316c2179bc1bcc1f8f8fa
|
@@ -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
|
74
|
-
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
|
34
|
-
other.is_a?(self.class) && self.class.significant_fields.all? { |elem| 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(
|
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
|
-
|
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
|
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
|
9
|
+
def initialize(metrics_listener, logger, **options)
|
10
10
|
@metrics_listener = metrics_listener
|
11
11
|
@log = logger
|
12
|
-
@all_channels = options[:channels]
|
13
|
-
@lock =
|
14
|
-
@
|
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
|
-
|
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
|
-
|
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
|
-
@
|
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
|
-
|
10
|
+
writers.present?
|
18
11
|
end
|
19
12
|
|
20
13
|
def has_routers_and_readers?
|
21
|
-
|
14
|
+
routers.present? && readers.present?
|
22
15
|
end
|
23
16
|
|
24
17
|
def self.parse(record, now)
|
25
|
-
return
|
26
|
-
new(expiration_timestamp: expiration_timestamp(now, record), database_name: record[
|
27
|
-
**record[
|
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
|
-
|
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 :
|
5
|
+
attr_reader :cluster_composition, :resolved_initial_routers
|
6
6
|
|
7
7
|
def initialize(composition, resolved_initial_routers = nil)
|
8
|
-
@
|
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
|
-
|
8
|
-
|
9
|
-
def initialize(of_database, clock, routing_addresses)
|
7
|
+
def initialize(of_database, _clock, *routing_addresses)
|
10
8
|
@database_name = of_database
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@
|
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
|
-
|
23
|
-
@expiration_timestamp
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
52
|
+
@table_lock.with_read_lock { @readers }
|
60
53
|
end
|
61
54
|
|
62
55
|
def writers
|
63
|
-
|
56
|
+
@table_lock.with_read_lock { @writers }
|
64
57
|
end
|
65
58
|
|
66
59
|
def routers
|
67
|
-
|
60
|
+
@table_lock.with_read_lock { @routers }
|
68
61
|
end
|
69
62
|
|
70
63
|
def servers
|
71
|
-
|
72
|
-
|
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
|
-
|
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
|
-
|
85
|
+
@table_lock.with_read_lock { @prefer_initial_router }
|
93
86
|
end
|
94
87
|
|
95
88
|
def expiration_timestamp
|
96
|
-
|
89
|
+
@table_lock.with_read_lock { @expiration_timestamp }
|
97
90
|
end
|
98
91
|
|
99
92
|
def to_s
|
100
|
-
|
101
|
-
"Ttl #{@expiration_timestamp}, currentTime #{
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb
CHANGED
@@ -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
|
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 =
|
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
|
55
|
+
index = (index + 1) % size
|
56
56
|
|
57
|
-
break if 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)
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
48
|
-
|
49
|
-
|
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
|
-
|
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
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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)
|
78
|
-
|
79
|
-
|
80
|
-
|
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,
|
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
|
-
|
93
|
-
|
94
|
-
attempt_errors.each
|
95
|
-
|
96
|
-
@log.error(
|
97
|
-
|
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
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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,
|
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 =
|
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
|
-
|
24
|
-
|
25
|
-
|
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)
|