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.
- 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/config.rb +1 -1
- data/ruby/neo4j/driver/graph_database.rb +2 -2
- data/ruby/neo4j/driver/internal/async/inbound/inbound_message_dispatcher.rb +2 -3
- 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/async/unmanaged_transaction.rb +18 -20
- 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 +38 -55
- 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 +15 -19
- data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +31 -19
- data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +12 -15
- 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/commit_tx_response_handler.rb +4 -4
- data/ruby/neo4j/driver/internal/handlers/legacy_pull_all_response_handler.rb +90 -51
- data/ruby/neo4j/driver/internal/handlers/pulln/auto_pull_response_handler.rb +33 -44
- data/ruby/neo4j/driver/internal/handlers/rollback_tx_response_handler.rb +7 -1
- 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/internal_result.rb +5 -5
- data/ruby/neo4j/driver/internal/internal_session.rb +1 -1
- data/ruby/neo4j/driver/internal/internal_transaction.rb +4 -4
- 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/abstract_streaming_message.rb +4 -1
- 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 +8 -4
- 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/internal/util/result_holder.rb +70 -0
- 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 +16 -14
- data/ruby/neo4j/driver/internal/database_name.rb +0 -12
@@ -6,109 +6,88 @@ module Neo4j::Driver
|
|
6
6
|
|
7
7
|
delegate :servers, to: :routing_table
|
8
8
|
|
9
|
-
def initialize(routing_table, rediscovery, connection_pool, routing_table_registry, logger,
|
9
|
+
def initialize(routing_table, rediscovery, connection_pool, routing_table_registry, logger, routing_table_purge_delay)
|
10
10
|
@routing_table = routing_table
|
11
11
|
@database_name = routing_table.database
|
12
12
|
@rediscovery = rediscovery
|
13
13
|
@connection_pool = connection_pool
|
14
14
|
@routing_table_registry = routing_table_registry
|
15
15
|
@log = logger
|
16
|
-
@
|
17
|
-
@
|
18
|
-
@refresh_routing_table_future = nil
|
16
|
+
@routing_table_purge_delay = routing_table_purge_delay
|
17
|
+
@mutex = Concurrent::ReentrantReadWriteLock.new
|
19
18
|
end
|
20
19
|
|
21
20
|
def on_connection_failure(address)
|
22
21
|
# remove server from the routing table, to prevent concurrent threads from making connections to this address
|
23
|
-
routing_table.forget(address)
|
22
|
+
@routing_table.forget(address)
|
24
23
|
end
|
25
24
|
|
26
25
|
def on_write_failure(address)
|
27
|
-
routing_table.forget_writer(address)
|
26
|
+
@routing_table.forget_writer(address)
|
28
27
|
end
|
29
28
|
|
30
29
|
def ensure_routing_table(context)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
error = Util::Futures.completion_exception_cause(completion_error)
|
43
|
-
|
44
|
-
if error.nil?
|
45
|
-
fresh_cluster_composition_fetched(composition)
|
46
|
-
else
|
47
|
-
cluster_composition_lookup_failed(error)
|
48
|
-
end
|
30
|
+
@mutex.with_write_lock do
|
31
|
+
if @routing_table.stale_for?(context.mode)
|
32
|
+
# existing routing table is not fresh and should be updated
|
33
|
+
@log.debug("Routing table for database '#{@database_name.description}' is stale. #{@routing_table}")
|
34
|
+
|
35
|
+
fresh_cluster_composition_fetched(
|
36
|
+
@rediscovery.lookup_cluster_composition(@routing_table, @connection_pool, context.rediscovery_bookmark,
|
37
|
+
nil))
|
38
|
+
else
|
39
|
+
# existing routing table is fresh, use it
|
40
|
+
@routing_table
|
49
41
|
end
|
50
|
-
|
51
|
-
|
52
|
-
else
|
53
|
-
# existing routing table is fresh, use it
|
54
|
-
java.util.concurrent.CompletableFuture.completed_future(routing_table)
|
42
|
+
rescue => error
|
43
|
+
cluster_composition_lookup_failed(error)
|
55
44
|
end
|
56
45
|
end
|
57
46
|
|
58
47
|
def update_routing_table(composition_lookup_result)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
return java.util.concurrent.CompletableFuture.completed_future(routing_table)
|
48
|
+
@mutex.with_write_lock do
|
49
|
+
if composition_lookup_result.cluster_composition.expiration_timestamp < @routing_table.expiration_timestamp
|
50
|
+
@routing_table
|
51
|
+
else
|
52
|
+
fresh_cluster_composition_fetched(composition_lookup_result)
|
65
53
|
end
|
66
|
-
|
67
|
-
result_future = java.util.concurrent.CompletableFuture.new
|
68
|
-
@refresh_routing_table_future = result_future
|
69
|
-
fresh_cluster_composition_fetched(composition_lookup_result)
|
70
|
-
result_future
|
71
54
|
end
|
72
55
|
end
|
73
56
|
|
74
|
-
private
|
75
|
-
begin
|
76
|
-
@log.debug("Fetched cluster composition for database '#{@database_name.description}'. #{composition_lookup_result.cluster_composition}")
|
77
|
-
routing_table.update(composition_lookup_result.cluster_composition)
|
78
|
-
@routing_table_registry.remove_aged
|
57
|
+
private
|
79
58
|
|
80
|
-
|
81
|
-
|
59
|
+
def fresh_cluster_composition_fetched(composition_lookup_result)
|
60
|
+
@log.debug("Fetched cluster composition for database '#{@database_name.description}'. #{composition_lookup_result.cluster_composition}")
|
61
|
+
@routing_table.update(composition_lookup_result.cluster_composition)
|
62
|
+
@routing_table_registry.remove_aged
|
63
|
+
addresses_to_retain = @routing_table_registry.all_servers.map(&:unicast_stream).reduce(&:+)
|
82
64
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
65
|
+
composition_lookup_result.resolved_initial_routers&.then do |addresses|
|
66
|
+
addresses_to_retain << addresses
|
67
|
+
end
|
87
68
|
|
88
|
-
|
89
|
-
@connection_pool.retain_all(addresses_to_retain)
|
69
|
+
@connection_pool.retain_all(addresses_to_retain)
|
90
70
|
|
91
|
-
|
71
|
+
@log.debug("Updated routing table for database '#{@database_name.description}'. #{routing_table}")
|
72
|
+
@routing_table
|
73
|
+
rescue => error
|
74
|
+
cluster_composition_lookup_failed(error)
|
75
|
+
end
|
92
76
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
rescue StandardError => error
|
97
|
-
cluster_composition_lookup_failed(error)
|
77
|
+
def cluster_composition_lookup_failed(error)
|
78
|
+
@log.error do
|
79
|
+
"Failed to update routing table for database '#{@database_name.description}'. Current routing table: #{@routing_table}."
|
98
80
|
end
|
81
|
+
@log.error(error)
|
82
|
+
@routing_table_registry.remove(@database_name)
|
83
|
+
raise error
|
99
84
|
end
|
100
85
|
|
101
|
-
|
102
|
-
@log.error("Failed to update routing table for database '#{database_name.description}'. Current routing table: #{routing_table}.", error)
|
103
|
-
@routing_table_registry.remove(database_name)
|
104
|
-
routing_table_future = @refresh_routing_table_future
|
105
|
-
@refresh_routing_table_future = nil
|
106
|
-
routing_table_future.complete_exceptionally(error)
|
107
|
-
end
|
86
|
+
public
|
108
87
|
|
109
88
|
# This method cannot be synchronized as it will be visited by all routing table handler's threads concurrently
|
110
89
|
def routing_table_aged?
|
111
|
-
@
|
90
|
+
@mutex.with_read_lock { @routing_table.has_been_stale_for?(@routing_table_purge_delay) }
|
112
91
|
end
|
113
92
|
end
|
114
93
|
end
|
@@ -2,78 +2,57 @@ module Neo4j::Driver
|
|
2
2
|
module Internal
|
3
3
|
module Cluster
|
4
4
|
class RoutingTableRegistryImpl
|
5
|
-
def initialize(connection_pool, rediscovery, clock, logger,
|
6
|
-
@factory = RoutingTableHandlerFactory.new(connection_pool, rediscovery, clock, logger,
|
7
|
-
@routing_table_handlers = Concurrent::
|
8
|
-
@
|
5
|
+
def initialize(connection_pool, rediscovery, clock, logger, routing_table_purge_delay)
|
6
|
+
@factory = RoutingTableHandlerFactory.new(connection_pool, rediscovery, clock, logger, routing_table_purge_delay)
|
7
|
+
@routing_table_handlers = Concurrent::Map.new
|
8
|
+
@principal_to_database_name = {}
|
9
9
|
@clock = clock
|
10
10
|
@connection_pool = connection_pool
|
11
11
|
@rediscovery = rediscovery
|
12
12
|
@log = logger
|
13
|
+
@mutex = Mutex.new
|
13
14
|
end
|
14
15
|
|
15
16
|
def ensure_routing_table(context)
|
16
|
-
ensure_database_name_is_completed(context)
|
17
|
-
|
18
|
-
|
19
|
-
handler.ensure_routing_table(completed_context).then_apply(-> (_ignored) { handler })
|
20
|
-
end
|
17
|
+
ctx_and_handler = ensure_database_name_is_completed(context)
|
18
|
+
(ctx_and_handler.handler || get_or_create(context.database_name))
|
19
|
+
.tap { |handler| handler.ensure_routing_table(ctx_and_handler.context) }
|
21
20
|
end
|
22
21
|
|
23
22
|
private def ensure_database_name_is_completed(context)
|
24
|
-
|
23
|
+
context_database_name = context.database_name
|
24
|
+
|
25
|
+
return ConnectionContextAndHandler.new(context, nil) if context_database_name
|
26
|
+
@mutex.synchronize do
|
27
|
+
return ConnectionContextAndHandler.new(context, nil) if context_database_name
|
25
28
|
|
26
|
-
if context_database_name_future.done?
|
27
|
-
context_and_handler_stage = java.util.concurrent.CompletableFuture.completed_future(ConnectionContextAndHandler.new(context, nil))
|
28
|
-
else
|
29
29
|
impersonated_user = context.impersonated_user
|
30
30
|
principal = Principal.new(impersonated_user)
|
31
|
-
|
32
|
-
handler_ref =
|
33
|
-
|
34
|
-
if database_name_stage.nil?
|
35
|
-
database_name_future = java.util.concurrent.CompletableFuture.new
|
36
|
-
@principal_to_database_name_stage[principal] = database_name_future
|
37
|
-
database_name_stage = database_name_future
|
38
|
-
|
39
|
-
routing_table = ClusterRoutingTable.new(DatabaseNameUtil::DEFAULT_DATABASE, @clock)
|
40
|
-
|
41
|
-
@rediscovery.lookup_cluster_composition(routing_table, @connection_pool, context.rediscovery_bookmark, impersonated_user).then_compose do |composition_lookup_result|
|
42
|
-
database_name = DatabaseNameUtil.database(composition_lookup_result.cluster_composition.database_name)
|
43
|
-
handler = get_or_create(database_name)
|
44
|
-
handler_ref.set(handler)
|
45
|
-
handler.update_routing_table(composition_lookup_result).then_apply(-> (_ignored) { database_name })
|
46
|
-
end.when_complete do |database_name, _throwable|
|
47
|
-
@principal_to_database_name_stage.delete(principal)
|
48
|
-
end.when_complete do |database_name, throwable|
|
49
|
-
if throwable.nil?
|
50
|
-
database_name_future.complete(database_name)
|
51
|
-
else
|
52
|
-
database_name_future.complete_exceptionally(throwable)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
31
|
+
database_name = @principal_to_database_name[principal]
|
32
|
+
handler_ref = Concurrent::AtomicReference.new
|
56
33
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
34
|
+
if database_name.nil?
|
35
|
+
@principal_to_database_name[principal] = database_name
|
36
|
+
|
37
|
+
routing_table = ClusterRoutingTable.new(DatabaseNameUtil.default_database, @clock)
|
38
|
+
|
39
|
+
composition_lookup_result = @rediscovery.lookup_cluster_composition(routing_table, @connection_pool, context.rediscovery_bookmark, impersonated_user)
|
40
|
+
database_name = DatabaseNameUtil.database(composition_lookup_result.cluster_composition.database_name)
|
41
|
+
handler = get_or_create(database_name)
|
42
|
+
handler_ref.set(handler)
|
43
|
+
handler.update_routing_table(composition_lookup_result)
|
44
|
+
@principal_to_database_name.delete(principal)
|
61
45
|
end
|
62
|
-
end
|
63
46
|
|
64
|
-
|
47
|
+
context.database_name = database_name
|
48
|
+
ConnectionContextAndHandler.new(context, handler_ref.get)
|
49
|
+
end
|
65
50
|
end
|
66
51
|
|
67
52
|
def all_servers
|
68
53
|
# obviously we just had a snapshot of all servers in all routing tables
|
69
54
|
# after we read it, the set could already be changed.
|
70
|
-
servers
|
71
|
-
|
72
|
-
@routing_table_handlers.values.each do |table_handler|
|
73
|
-
servers << table_handler.servers
|
74
|
-
end
|
75
|
-
|
76
|
-
servers
|
55
|
+
@routing_table_handlers.values.map(&:servers).reduce(&:+)
|
77
56
|
end
|
78
57
|
|
79
58
|
def remove(database_name)
|
@@ -90,17 +69,19 @@ module Neo4j::Driver
|
|
90
69
|
end
|
91
70
|
end
|
92
71
|
|
93
|
-
def
|
94
|
-
|
72
|
+
def routing_table_handler(database_name)
|
73
|
+
database_name = DatabaseNameUtil.database(database_name) unless database_name.is_a?(InternalDatabaseName)
|
74
|
+
@routing_table_handlers[database_name]
|
95
75
|
end
|
96
76
|
|
97
|
-
|
98
|
-
|
99
|
-
end
|
77
|
+
# For tests
|
78
|
+
delegate :key?, to: :@routing_table_handlers
|
100
79
|
|
101
80
|
def get_or_create(database_name)
|
102
|
-
@routing_table_handlers.compute_if_absent(database_name) do
|
103
|
-
|
81
|
+
@routing_table_handlers.compute_if_absent(database_name) do
|
82
|
+
# TODO: Verify if applies
|
83
|
+
# Note: Atomic methods taking a block do not allow the self instance to be used within the block. Doing so will cause a deadlock.
|
84
|
+
handler = @factory.new_instance(database_name, self)
|
104
85
|
@log.debug("Routing table handler for database '#{database_name.description}' is added.")
|
105
86
|
handler
|
106
87
|
end
|
@@ -109,17 +90,17 @@ module Neo4j::Driver
|
|
109
90
|
private
|
110
91
|
|
111
92
|
class RoutingTableHandlerFactory
|
112
|
-
def initialize(connection_pool, rediscovery, clock, logger,
|
93
|
+
def initialize(connection_pool, rediscovery, clock, logger, routing_table_purge_delay)
|
113
94
|
@connection_pool = connection_pool
|
114
95
|
@rediscovery = rediscovery
|
115
96
|
@clock = clock
|
116
97
|
@logger = logger
|
117
|
-
@
|
98
|
+
@routing_table_purge_delay = routing_table_purge_delay
|
118
99
|
end
|
119
100
|
|
120
101
|
def new_instance(database_name, all_tables)
|
121
102
|
routing_table = ClusterRoutingTable.new(database_name, @clock)
|
122
|
-
RoutingTableHandlerImpl.new(routing_table, @rediscovery, @connection_pool, all_tables, @logger, @
|
103
|
+
RoutingTableHandlerImpl.new(routing_table, @rediscovery, @connection_pool, all_tables, @logger, @routing_table_purge_delay)
|
123
104
|
end
|
124
105
|
end
|
125
106
|
|
@@ -5,7 +5,7 @@ module Neo4j::Driver
|
|
5
5
|
# This implementation of the {@link RoutingProcedureRunner} works with single database versions of Neo4j calling
|
6
6
|
# the procedure `dbms.cluster.routing.getRoutingTable`
|
7
7
|
class SingleDatabaseRoutingProcedureRunner
|
8
|
-
ROUTING_CONTEXT =
|
8
|
+
ROUTING_CONTEXT = :context
|
9
9
|
GET_ROUTING_TABLE = "CALL dbms.cluster.routing.getRoutingTable($#{ROUTING_CONTEXT})"
|
10
10
|
|
11
11
|
def initialize(context)
|
@@ -16,17 +16,15 @@ module Neo4j::Driver
|
|
16
16
|
delegate = connection(connection)
|
17
17
|
procedure = procedure_query(connection.server_version, database_name)
|
18
18
|
bookmark_holder = bookmark_holder(bookmark)
|
19
|
-
run_procedure(delegate, procedure, bookmark_holder)
|
20
|
-
release_connection(delegate
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
19
|
+
run_procedure(delegate, procedure, bookmark_holder)
|
20
|
+
.side { release_connection(delegate) }
|
21
|
+
.chain { |records, error| process_procedure_response(procedure, records, error) }
|
24
22
|
end
|
25
23
|
|
26
24
|
private
|
27
25
|
|
28
26
|
def connection(connection)
|
29
|
-
Async::Connection::DirectConnection.new(connection, default_database, AccessMode::WRITE, nil)
|
27
|
+
Async::Connection::DirectConnection.new(connection, DatabaseNameUtil.default_database, AccessMode::WRITE, nil)
|
30
28
|
end
|
31
29
|
|
32
30
|
def procedure_query(server_version, database_name)
|
@@ -34,7 +32,7 @@ module Neo4j::Driver
|
|
34
32
|
raise Exceptions::FatalDiscoveryException, "Refreshing routing table for multi-databases is not supported in server version lower than 4.0. Current server version: #{server_version}. Database name: '#{database_name.description}'"
|
35
33
|
end
|
36
34
|
|
37
|
-
Query.new(GET_ROUTING_TABLE,
|
35
|
+
Query.new(GET_ROUTING_TABLE, ROUTING_CONTEXT => @context.to_h)
|
38
36
|
end
|
39
37
|
|
40
38
|
def bookmark_holder(_ignored)
|
@@ -45,30 +43,28 @@ module Neo4j::Driver
|
|
45
43
|
connection.protocol
|
46
44
|
.run_in_auto_commit_transaction(connection, procedure, bookmark_holder, TransactionConfig.empty,
|
47
45
|
Handlers::Pulln::FetchSizeUtil::UNLIMITED_FETCH_SIZE)
|
48
|
-
.async_result.
|
46
|
+
.async_result.then(&:to_a)
|
49
47
|
end
|
50
48
|
|
51
|
-
def release_connection(connection
|
49
|
+
def release_connection(connection)
|
52
50
|
# It is not strictly required to release connection after routing procedure invocation because it'll
|
53
51
|
# be released by the PULL_ALL response handler after result is fully fetched. Such release will happen
|
54
52
|
# in background. However, releasing it early as part of whole chain makes it easier to reason about
|
55
53
|
# rediscovery in stub server tests. Some of them assume connections to instances not present in new
|
56
54
|
# routing table will be closed immediately.
|
57
|
-
connection.release
|
55
|
+
connection.release
|
58
56
|
end
|
59
57
|
|
60
58
|
def process_procedure_response(procedure, records, error)
|
61
|
-
|
62
|
-
|
63
|
-
return RoutingProcedureResponse.new(procedure, records) if cause.nil?
|
64
|
-
|
65
|
-
handle_error(procedure, cause)
|
59
|
+
error ? handle_error(procedure, error) : RoutingProcedureResponse.new(procedure, records: records)
|
66
60
|
end
|
67
61
|
|
68
62
|
def handle_error(procedure, error)
|
69
|
-
|
70
|
-
|
71
|
-
|
63
|
+
if error.is_a? Exceptions::ClientException
|
64
|
+
RoutingProcedureResponse.new(procedure, error: error)
|
65
|
+
else
|
66
|
+
raise error
|
67
|
+
end
|
72
68
|
end
|
73
69
|
end
|
74
70
|
end
|
@@ -2,6 +2,7 @@ module Neo4j::Driver
|
|
2
2
|
module Internal
|
3
3
|
module Cursor
|
4
4
|
class AsyncResultCursorImpl
|
5
|
+
include Enumerable
|
5
6
|
delegate :consume_async, :next_async, :peek_async, to: :@pull_all_handler
|
6
7
|
|
7
8
|
def initialize(run_handler, pull_all_handler)
|
@@ -14,20 +15,24 @@ module Neo4j::Driver
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def single_async
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
next_async.compose do |first_record|
|
19
|
+
unless first_record
|
20
|
+
raise Exceptions::NoSuchRecordException, 'Cannot retrieve a single record, because this result is empty.'
|
21
|
+
end
|
22
|
+
next_async.then do |second_record|
|
23
|
+
if second_record
|
24
|
+
raise Exceptions::NoSuchRecordException,
|
25
|
+
'Expected a result with a single record, but this result contains at least one more. Ensure your query returns only one record.'
|
26
|
+
end
|
27
|
+
first_record
|
28
|
+
end
|
24
29
|
end
|
25
|
-
first_record
|
26
30
|
end
|
27
31
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
32
|
+
def each(&action)
|
33
|
+
result_holder = Util::ResultHolder.new
|
34
|
+
internal_for_each_async(result_holder, &action)
|
35
|
+
result_holder.then { consume_async }
|
31
36
|
end
|
32
37
|
|
33
38
|
def to_async(&map_function)
|
@@ -36,7 +41,7 @@ module Neo4j::Driver
|
|
36
41
|
|
37
42
|
def discard_all_failure_async
|
38
43
|
# runError has priority over other errors and is expected to have been reported to user by now
|
39
|
-
consume_async
|
44
|
+
consume_async.chain { |_summary, error| run_error ? nil : error }
|
40
45
|
nil
|
41
46
|
end
|
42
47
|
|
@@ -45,18 +50,25 @@ module Neo4j::Driver
|
|
45
50
|
@pull_all_handler.pull_all_failure_async.then { |error| run_error ? nil : error }
|
46
51
|
end
|
47
52
|
|
48
|
-
private def internal_for_each_async
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
53
|
+
private def internal_for_each_async(result_holder, &action)
|
54
|
+
next_async.chain do |record, error|
|
55
|
+
if error
|
56
|
+
result_holder.fail(error)
|
57
|
+
elsif record
|
58
|
+
begin
|
59
|
+
yield record
|
60
|
+
rescue => action_error
|
61
|
+
result_holder.fail(action_error)
|
62
|
+
end
|
63
|
+
internal_for_each_async(result_holder, &action)
|
64
|
+
else
|
65
|
+
result_holder.succeed(nil)
|
54
66
|
end
|
55
67
|
end
|
56
68
|
end
|
57
69
|
|
58
70
|
def map_successful_run_completion_async
|
59
|
-
run_error || self
|
71
|
+
run_error&.then(&Util::ResultHolder.method(:failed)) || Util::ResultHolder.successful(self)
|
60
72
|
end
|
61
73
|
|
62
74
|
def run_error
|
@@ -2,6 +2,7 @@ module Neo4j::Driver
|
|
2
2
|
module Internal
|
3
3
|
module Cursor
|
4
4
|
class DisposableAsyncResultCursor
|
5
|
+
include Enumerable
|
5
6
|
delegate :keys, :pull_all_failure_async, to: :@delegate
|
6
7
|
|
7
8
|
def initialize(delegate)
|
@@ -14,25 +15,23 @@ module Neo4j::Driver
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def next_async
|
17
|
-
assert_not_disposed
|
18
|
+
assert_not_disposed
|
19
|
+
@delegate.next_async
|
18
20
|
end
|
19
21
|
|
20
22
|
def peek_async
|
21
|
-
assert_not_disposed
|
23
|
+
assert_not_disposed
|
24
|
+
@delegate.peek_async
|
22
25
|
end
|
23
26
|
|
24
27
|
def single_async
|
25
|
-
assert_not_disposed
|
28
|
+
assert_not_disposed
|
29
|
+
@delegate.single_async
|
26
30
|
end
|
27
31
|
|
28
|
-
def
|
29
|
-
assert_not_disposed
|
30
|
-
|
31
|
-
|
32
|
-
def list_async(map_function = nil)
|
33
|
-
return assert_not_disposed.then_compose(-> (_ignored) { @delegate.list_async(map_function) }) if map_function.present?
|
34
|
-
|
35
|
-
assert_not_disposed.then_compose(-> (_ignored) { @delegate.list_async })
|
32
|
+
def each(&action)
|
33
|
+
assert_not_disposed
|
34
|
+
@delegate.each(&action)
|
36
35
|
end
|
37
36
|
|
38
37
|
def discard_all_failure_async
|
@@ -41,9 +40,7 @@ module Neo4j::Driver
|
|
41
40
|
end
|
42
41
|
|
43
42
|
private def assert_not_disposed
|
44
|
-
|
45
|
-
|
46
|
-
Util::Futures.completed_with_null
|
43
|
+
raise Util::ErrorUtil.new_result_consumed_error if @disposed
|
47
44
|
end
|
48
45
|
|
49
46
|
def disposed?
|
@@ -51,7 +48,7 @@ module Neo4j::Driver
|
|
51
48
|
end
|
52
49
|
|
53
50
|
def map_successful_run_completion_async
|
54
|
-
@delegate.map_successful_run_completion_async
|
51
|
+
@delegate.map_successful_run_completion_async.then { self }
|
55
52
|
end
|
56
53
|
end
|
57
54
|
end
|
@@ -6,8 +6,8 @@ module Neo4j::Driver
|
|
6
6
|
|
7
7
|
private
|
8
8
|
|
9
|
-
DEFAULT_DATABASE =
|
10
|
-
SYSTEM_DATABASE = InternalDatabaseName.new(SYSTEM_DATABASE_NAME)
|
9
|
+
DEFAULT_DATABASE = InternalDatabaseName.new(description: '<default database>')
|
10
|
+
SYSTEM_DATABASE = InternalDatabaseName.new(database_name: SYSTEM_DATABASE_NAME)
|
11
11
|
|
12
12
|
public
|
13
13
|
|
@@ -27,7 +27,7 @@ module Neo4j::Driver
|
|
27
27
|
when SYSTEM_DATABASE_NAME
|
28
28
|
system_database
|
29
29
|
else
|
30
|
-
InternalDatabaseName.new(name)
|
30
|
+
InternalDatabaseName.new(database_name: name)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -1,12 +1,6 @@
|
|
1
1
|
module Neo4j::Driver
|
2
2
|
module Internal
|
3
|
-
class DefaultBookmarkHolder
|
4
|
-
attr_reader :bookmark
|
5
|
-
|
6
|
-
def initialize(bookmark = InternalBookmark.empty)
|
7
|
-
@bookmark = bookmark
|
8
|
-
end
|
9
|
-
|
3
|
+
class DefaultBookmarkHolder < ReadOnlyBookmarkHolder
|
10
4
|
def bookmark=(bookmark)
|
11
5
|
@bookmark = bookmark if bookmark.present?
|
12
6
|
end
|
@@ -83,8 +83,8 @@ module Neo4j::Driver::Internal
|
|
83
83
|
driver(:Direct, securityPlan, address, connection_provider, retryLogic, metricsProvider, config)
|
84
84
|
end
|
85
85
|
|
86
|
-
def create_routing_driver(securityPlan, address, connection_pool, eventExecutorGroup,
|
87
|
-
connection_provider = create_load_balancer(address, connection_pool, eventExecutorGroup, config,
|
86
|
+
def create_routing_driver(securityPlan, address, connection_pool, eventExecutorGroup, routing_settings, retryLogic, metricsProvider, config)
|
87
|
+
connection_provider = create_load_balancer(address, connection_pool, eventExecutorGroup, config, routing_settings)
|
88
88
|
driver(:Routing, securityPlan, address, connection_provider, retryLogic, metricsProvider, config)
|
89
89
|
end
|
90
90
|
|
@@ -95,11 +95,11 @@ module Neo4j::Driver::Internal
|
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
|
-
def create_load_balancer(address, connection_pool, eventExecutorGroup, config,
|
98
|
+
def create_load_balancer(address, connection_pool, eventExecutorGroup, config, routing_settings)
|
99
99
|
load_balancing_strategy = Cluster::Loadbalancing::LeastConnectedLoadBalancingStrategy.new(connection_pool, config[:logger])
|
100
100
|
resolver = create_resolver(config)
|
101
101
|
Cluster::Loadbalancing::LoadBalancer.new(
|
102
|
-
address,
|
102
|
+
address, routing_settings, connection_pool, eventExecutorGroup,
|
103
103
|
config[:logger], load_balancing_strategy, resolver, &method(:domain_name_resolver))
|
104
104
|
end
|
105
105
|
|
@@ -4,16 +4,16 @@ module Neo4j::Driver
|
|
4
4
|
class CommitTxResponseHandler
|
5
5
|
include Spi::ResponseHandler
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
@
|
7
|
+
def initialize(result_holder)
|
8
|
+
@result_holder = result_holder
|
9
9
|
end
|
10
10
|
|
11
11
|
def on_success(metadata)
|
12
|
-
@
|
12
|
+
@result_holder.succeed(metadata[:bookmark]&.then(&InternalBookmark.method(:parse)))
|
13
13
|
end
|
14
14
|
|
15
15
|
def on_failure(error)
|
16
|
-
|
16
|
+
@result_holder.fail(error)
|
17
17
|
end
|
18
18
|
|
19
19
|
def on_record(fields)
|