neo4j-ruby-driver 4.4.0.alpha.9 → 4.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 41dc794832386239a05ddcc44bb1937da85f8d1b3d0be4977ab3b53157ab5ac0
4
- data.tar.gz: e085f6bfce9255985ead9e0aab6bd70a8495f9b62bbfa16fbe38efaac1508032
3
+ metadata.gz: aad2e30fa3fa23dc95e7db9f27847b1c5382c23600c019d93a7625fc5a66d085
4
+ data.tar.gz: 534c14f354f92df7a85b153e1451951ded71863fbbb10c61a50a280a8bf3bea7
5
5
  SHA512:
6
- metadata.gz: d3eeaeaeb2a4f8d19ffacdec93f2fb64ff5c8a65ab27bf6593d4ae3ce2c08e092b97662bd6ab58f4cc59a5bb4d2215e1c8fe80c916c05eda9e9b9454b72411a5
7
- data.tar.gz: 0a86332ba42e153c1f21964fbca5a0cdba75bf5b3cea574ce40db4a1a54f090dd43d1b1f6096acb51e04ac7d6cdddaf03a3f84dad6fb4582de911d11f22824b5
6
+ metadata.gz: 909be9c6542e378161b3e9b9c62ad9e45ef08c54f7410b4ea5a2ba3f15267fd445995757f74210aadcaa10f94475f839cddeb2294c23d44a9925e044e23cc162
7
+ data.tar.gz: 4d22446e5a24c6f7f99072202bfc4dbab1e222b535c64b1c716a31f4993f9fe0da07c8d5dfbd3f68d793fc1b11f6782f4a6062e3171f41b7b26a8c7260b0966a
@@ -66,7 +66,7 @@ module Neo4j::Driver
66
66
 
67
67
  def close_driver(driver, uri, log)
68
68
  driver.close
69
- rescue StandardError => close_error
69
+ rescue => close_error
70
70
  log.warn { "Unable to close driver towards URI: #{uri}\n#{close_error}" }
71
71
  end
72
72
 
@@ -1,14 +1,13 @@
1
1
  module Neo4j::Driver
2
2
  module Internal
3
3
  module Async
4
- class NetworkConnection < ::Async::Pool::Resource
4
+ class NetworkConnection
5
5
  include Spi::Connection
6
6
  delegate :protocol, to: :@channel
7
7
 
8
8
  attr_reader :server_agent, :server_address, :server_version
9
9
 
10
- def initialize(channel, channel_pool, logger)
11
- super()
10
+ def initialize(channel, channel_pool, logger, &on_pool_shutdown)
12
11
  @log = logger
13
12
  @channel = channel
14
13
  @message_dispatcher = channel.attributes[:message_dispatcher]
@@ -17,17 +16,13 @@ module Neo4j::Driver
17
16
  @server_version = channel.attributes[:server_version]
18
17
  @protocol = Messaging::BoltProtocol.for_channel(channel)
19
18
  @channel_pool = channel_pool
19
+ @on_pool_shutdow = on_pool_shutdown
20
20
  # @release_future = java.util.concurrent.CompletableFuture.new
21
21
  # @clock = clock
22
22
  # @connection_read_timeout = Connection::ChannelAttributes.connection_read_timeout(channel) || nil
23
23
  @status = Concurrent::AtomicReference.new(Status::OPEN)
24
24
  end
25
25
 
26
- # def close
27
- # super
28
- # @io.close
29
- # end
30
-
31
26
  def open?
32
27
  @status.get == Status::OPEN
33
28
  end
@@ -95,10 +90,25 @@ module Neo4j::Driver
95
90
  # auto-read could've been disabled, re-enable it to automatically receive response for RESET
96
91
  @channel.auto_read = true
97
92
  @message_dispatcher.enqueue(reset_handler)
98
- @channel.write_and_flush(Messaging::Request::ResetMessage::RESET) #.add_listener(-> (_future) { register_connection_read_timeout(@channel) })
93
+ write_to_channel(Messaging::Request::ResetMessage::RESET, true)
99
94
  end
100
95
  end
101
96
 
97
+ def write_to_channel(message, flush = false)
98
+ if flush
99
+ @channel.write_and_flush(message) #.add_listener(-> (_future) { register_connection_read_timeout(@channel) })
100
+ else
101
+ @channel.write(message)
102
+ end
103
+ rescue EOFError, Errno::ECONNRESET, Errno::EPIPE => e
104
+ terminate_and_release(e.message)
105
+ @log.debug("Shutting down connection pool towards #{@server_address} due to error: #{e.message}")
106
+ @channel_pool.shutdown(&:close)
107
+ @on_pool_shutdow.call
108
+ # should remove routing table entry as well
109
+ raise Exceptions::SessionExpiredException, e.message
110
+ end
111
+
102
112
  def flush_in_event_loop
103
113
  @channel.event_loop.execute do
104
114
  @channel.flush
@@ -109,11 +119,7 @@ module Neo4j::Driver
109
119
  def write_message_in_event_loop(message, handler, flush)
110
120
  @message_dispatcher.enqueue(handler)
111
121
 
112
- if flush
113
- @channel.write_and_flush(message) #.add_listener(-> (_future) { register_connection_read_timeout(@channel) })
114
- else
115
- @channel.write(message)
116
- end
122
+ write_to_channel(message, flush)
117
123
  end
118
124
 
119
125
  def write_messages_in_event_loop(message1, handler1, message2, handler2, flush)
@@ -2,14 +2,13 @@ module Neo4j::Driver
2
2
  module Internal
3
3
  module Async
4
4
  module Pool
5
- class Channel < ::Async::Pool::Resource
5
+ class Channel
6
6
  attr :stream
7
7
  attr_accessor :version, :protocol, :message_format, :message_dispatcher
8
8
  attr :attributes # should be attr
9
9
  attr_accessor :auto_read
10
10
 
11
11
  def initialize(address, connector, logger)
12
- super()
13
12
  @attributes = Connection::ChannelAttributes.new
14
13
  @stream = Connection::Stream.new(connector.connect(address))
15
14
  @stream.write(Connection::BoltProtocolUtil.handshake_buf)
@@ -25,7 +24,6 @@ module Neo4j::Driver
25
24
  end
26
25
 
27
26
  def close
28
- super unless closed? # Should this be conditional?
29
27
  @stream.close
30
28
  end
31
29
 
@@ -0,0 +1,31 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Async
4
+ module Pool
5
+ class ChannelPool < ConnectionPool
6
+ def initialize(limit: nil, acquisition_timeout: nil, &block)
7
+ super(size: limit, timeout: acquisition_timeout, &block)
8
+ @available = TimedStack.new(@size, &block)
9
+ end
10
+
11
+ def acquire(options = {})
12
+ @available.pop(options[:timeout] || @timeout)
13
+ end
14
+
15
+ def release(resource)
16
+ @available.push(resource)
17
+ nil
18
+ end
19
+
20
+ def close
21
+ @available.shutdown(&:close)
22
+ end
23
+
24
+ def busy?
25
+ @available.any_resource_busy?
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -20,12 +20,12 @@ module Neo4j::Driver
20
20
 
21
21
  begin
22
22
  channel = pool.acquire
23
- @log.debug{"Channel #{channel.object_id} acquired"}
23
+ @log.debug { "Channel #{channel.object_id} acquired" }
24
24
  rescue => error
25
25
  process_acquisition_error(pool, address, error)
26
26
  end
27
27
  assert_not_closed(address, channel, pool)
28
- NetworkConnection.new(channel, pool, @log)
28
+ NetworkConnection.new(channel, pool, @log) { remove(pool) }
29
29
  end
30
30
 
31
31
  def retain_all(addresses_to_retain)
@@ -46,6 +46,12 @@ module Neo4j::Driver
46
46
  end
47
47
  end
48
48
 
49
+ def remove(pool)
50
+ @address_to_pool_lock.with_write_lock do
51
+ @address_to_pool.each { |address, value| @address_to_pool.delete(address) if value == pool }
52
+ end
53
+ end
54
+
49
55
  def in_use_connections(address)
50
56
  @address_to_pool[address]&.size || 0
51
57
  # @netty_channel_tracker.in_use_channel_count(address)
@@ -77,11 +83,11 @@ module Neo4j::Driver
77
83
  private
78
84
 
79
85
  def process_acquisition_error(pool, server_address, error)
80
- if error.is_a?(::Async::TimeoutError)
86
+ if error.is_a?(ConnectionPool::TimeoutError)
81
87
  # NettyChannelPool returns future failed with TimeoutException if acquire operation takes more than
82
88
  # configured time, translate this exception to a prettier one and re-throw
83
89
  raise Neo4j::Driver::Exceptions::ClientException.new("Unable to acquire connection from the pool within configured maximum time of #{@settings.connection_acquisition_timeout.inspect}")
84
- # elsif pool.closed?
90
+ # elsif pool.closed?
85
91
  # There is a race condition where a thread tries to acquire a connection while the pool is closed by another concurrent thread.
86
92
  # Treat as failed to obtain connection for a direct driver. For a routing driver, this error should be retried.
87
93
  # raise Neo4j::Driver::Exceptions::ServiceUnavailableException, "Connection pool for server #{server_address} is closed while acquiring a connection."
@@ -109,7 +115,7 @@ module Neo4j::Driver
109
115
  end
110
116
 
111
117
  def new_pool(address)
112
- Controller.wrap(limit: @settings.max_connection_pool_size, acquisition_timeout: @settings.connection_acquisition_timeout) { Channel.new(address, @connector, @log) }
118
+ ChannelPool.new(limit: @settings.max_connection_pool_size, acquisition_timeout: @settings.connection_acquisition_timeout) { Channel.new(address, @connector, @log) }
113
119
  end
114
120
 
115
121
  def get_or_create_pool(address)
@@ -0,0 +1,15 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Async
4
+ module Pool
5
+ class TimedStack < ConnectionPool::TimedStack
6
+ def any_resource_busy?
7
+ @mutex.synchronize do
8
+ @created > @que.length
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -41,13 +41,15 @@ module Neo4j::Driver
41
41
  def supports_multi_db?
42
42
  addresses = @rediscovery.resolve
43
43
  base_error = Exceptions::ServiceUnavailableException.new("Failed to perform multi-databases feature detection with the following servers: #{addresses}")
44
- addresses.lazy.map do |address|
45
- private_suports_multi_db?(address)
44
+ addresses.each do |address|
45
+ return private_suports_multi_db?(address)
46
46
  rescue Exceptions::SecurityException
47
47
  raise
48
48
  rescue => error
49
49
  Util::Futures.combine_errors(base_error, error)
50
- end.find { |result| !result.nil? } or raise base_error
50
+ end
51
+
52
+ raise base_error
51
53
  end
52
54
 
53
55
  private
@@ -12,19 +12,19 @@ module Neo4j::Driver
12
12
 
13
13
  def get_cluster_composition(connection, database_name, bookmark, impersonated_user)
14
14
  runner = if Messaging::Request::MultiDatabaseUtil.supports_route_message?(connection)
15
- @route_message_routing_procedure_runner
16
- elsif Messaging::Request::MultiDatabaseUtil.supports_multi_database?(connection)
17
- @multi_database_routing_procedure_runner
18
- else
19
- @single_database_routing_procedure_runner
20
- end
15
+ @route_message_routing_procedure_runner
16
+ elsif Messaging::Request::MultiDatabaseUtil.supports_multi_database?(connection)
17
+ @multi_database_routing_procedure_runner
18
+ else
19
+ @single_database_routing_procedure_runner
20
+ end
21
21
 
22
22
  process_routing_response(runner.run(connection, database_name, bookmark, impersonated_user))
23
23
  end
24
24
 
25
25
  def process_routing_response(response)
26
26
  unless response.success?
27
- raise response.error.class, "Failed to run '#{invoked_procedure_string(response)}' on server. Please make sure that there is a Neo4j server or cluster up running."
27
+ raise response.error, "Failed to run '#{invoked_procedure_string(response)}' on server. Please make sure that there is a Neo4j server or cluster up running."
28
28
  end
29
29
 
30
30
  records = response.records
@@ -36,7 +36,7 @@ module Neo4j::Driver
36
36
 
37
37
  # failed to parse the record
38
38
  begin
39
- cluster = ClusterComposition.parse( records[0], Time.now)
39
+ cluster = ClusterComposition.parse(records[0], Time.now)
40
40
  rescue Exceptions::Value::ValueException => e
41
41
  raise Exceptions::ProtocolException, "#{PROTOCOL_ERROR_MESSAGE % invoked_procedure_string(response)} unparsable record received. #{e}"
42
42
  end
@@ -17,8 +17,8 @@ module Neo4j::Driver
17
17
  procedure = procedure_query(connection.server_version, database_name)
18
18
  bookmark_holder = bookmark_holder(bookmark)
19
19
  begin
20
- records = run_procedure(delegate, procedure, bookmark_holder)
21
- RoutingProcedureResponse.new(procedure, records: records)
20
+ result = run_procedure(delegate, procedure, bookmark_holder)
21
+ RoutingProcedureResponse.new(procedure, **result.error ? { error: result.error } : { records: result.result! })
22
22
  rescue => error
23
23
  handle_error(procedure, error)
24
24
  ensure
@@ -48,7 +48,7 @@ module Neo4j::Driver
48
48
  connection.protocol
49
49
  .run_in_auto_commit_transaction(connection, procedure, bookmark_holder, TransactionConfig.empty,
50
50
  Handlers::Pulln::FetchSizeUtil::UNLIMITED_FETCH_SIZE)
51
- .async_result.then(&:to_a)
51
+ .async_result.list_async
52
52
  end
53
53
 
54
54
  def release_connection(connection)
@@ -2,7 +2,6 @@ module Neo4j::Driver
2
2
  module Internal
3
3
  module Cursor
4
4
  class AsyncResultCursorImpl
5
- include Enumerable
6
5
  delegate :consume_async, :next_async, :peek_async, to: :@pull_all_handler
7
6
 
8
7
  def initialize(run_handler, pull_all_handler)
@@ -29,13 +28,7 @@ module Neo4j::Driver
29
28
  end
30
29
  end
31
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 }
36
- end
37
-
38
- def to_async(&map_function)
31
+ def list_async(&map_function)
39
32
  @pull_all_handler.list_async(&block_given? ? map_function : :itself)
40
33
  end
41
34
 
@@ -49,23 +42,6 @@ module Neo4j::Driver
49
42
  @pull_all_handler.pull_all_failure_async.then { |error| run_error ? nil : error }
50
43
  end
51
44
 
52
- private def internal_for_each_async(result_holder, &action)
53
- next_async.chain do |record, error|
54
- if error
55
- result_holder.fail(error)
56
- elsif record
57
- begin
58
- yield record
59
- rescue => action_error
60
- result_holder.fail(action_error)
61
- end
62
- internal_for_each_async(result_holder, &action)
63
- else
64
- result_holder.succeed(nil)
65
- end
66
- end
67
- end
68
-
69
45
  def map_successful_run_completion_async
70
46
  run_error&.then(&Util::ResultHolder.method(:failed)) || Util::ResultHolder.successful(self)
71
47
  end
@@ -34,6 +34,11 @@ module Neo4j::Driver
34
34
  @delegate.each(&action)
35
35
  end
36
36
 
37
+ def list_async(&block)
38
+ assert_not_disposed
39
+ @delegate.list_async(&block)
40
+ end
41
+
37
42
  def discard_all_failure_async
38
43
  @disposed = true
39
44
  @delegate.discard_all_failure_async
@@ -4,7 +4,6 @@ module Neo4j::Driver
4
4
  # This is the Pull All response handler that handles pull all messages in Bolt v3 and previous protocol versions.
5
5
  class LegacyPullAllResponseHandler
6
6
  include Spi::ResponseHandler
7
- include Enumerable
8
7
  RECORD_BUFFER_LOW_WATERMARK = ENV['record_buffer_low_watermark']&.to_i || 300
9
8
  RECORD_BUFFER_HIGH_WATERMARK = ENV['record_buffer_high_watermark']&.to_i || 1000
10
9
 
@@ -83,12 +82,15 @@ module Neo4j::Driver
83
82
  Util::ResultHolder.successful(@summary)
84
83
  end
85
84
 
86
- def each
87
- pull_all_failure_async.then do
85
+ def list_async(&block)
86
+ pull_all_failure_async.then do |error|
87
+ raise error if error
88
88
  unless @finished
89
89
  raise Exceptions::IllegalStateException, "Can't get records as list because SUCCESS or FAILURE did not arrive"
90
90
  end
91
- @records.each { |record| yield record }
91
+ @records.items.map(&block)
92
+ ensure
93
+ @records.items.clear
92
94
  end
93
95
  end
94
96
 
@@ -3,7 +3,6 @@ module Neo4j::Driver
3
3
  module Handlers
4
4
  module Pulln
5
5
  class AutoPullResponseHandler < BasicPullResponseHandler
6
- include Enumerable
7
6
  delegate :signal, to: :@records
8
7
  LONG_MAX_VALUE = 2 ** 63 - 1
9
8
 
@@ -79,12 +78,14 @@ module Neo4j::Driver
79
78
  completed_with_value_if_no_failure(@summary)
80
79
  end
81
80
 
82
- def each
81
+ def list_async(&block)
83
82
  pull_all_async.then do
84
83
  unless done?
85
84
  raise Exceptions::IllegalStateException, "Can't get records as list because SUCCESS or FAILURE did not arrive"
86
85
  end
87
- @records.each { |record| yield record }
86
+ @records.items.map(&block)
87
+ ensure
88
+ @records.items.clear
88
89
  end
89
90
  end
90
91
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Neo4j
4
4
  module Driver
5
- VERSION = '4.4.0.alpha.9'
5
+ VERSION = '4.4.0'
6
6
  end
7
7
  end
data/ruby/neo4j/driver.rb CHANGED
@@ -5,9 +5,8 @@ require 'active_support/core_ext/hash/keys'
5
5
  require 'active_support/logger'
6
6
  require 'async/io'
7
7
  require 'async/io/stream'
8
- require 'async/pool'
9
- require 'async/pool/resource'
10
8
  require 'async/queue'
9
+ require 'connection_pool'
11
10
  require 'bigdecimal'
12
11
  require 'date'
13
12
  require 'loader'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neo4j-ruby-driver
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.0.alpha.9
4
+ version: 4.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Heinrich Klobuczek
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-24 00:00:00.000000000 Z
11
+ date: 2022-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: async-pool
56
+ name: connection_pool
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -287,13 +287,14 @@ files:
287
287
  - ruby/neo4j/driver/internal/async/outbound/chunk_aware_byte_buf_output.rb
288
288
  - ruby/neo4j/driver/internal/async/outbound/outbound_message_handler.rb
289
289
  - ruby/neo4j/driver/internal/async/pool/channel.rb
290
+ - ruby/neo4j/driver/internal/async/pool/channel_pool.rb
290
291
  - ruby/neo4j/driver/internal/async/pool/channel_tracker.rb
291
292
  - ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb
292
- - ruby/neo4j/driver/internal/async/pool/controller.rb
293
293
  - ruby/neo4j/driver/internal/async/pool/netty_channel_health_checker.rb
294
294
  - ruby/neo4j/driver/internal/async/pool/netty_channel_pool.rb
295
295
  - ruby/neo4j/driver/internal/async/pool/network_connection_factory.rb
296
296
  - ruby/neo4j/driver/internal/async/pool/pool_settings.rb
297
+ - ruby/neo4j/driver/internal/async/pool/timed_stack.rb
297
298
  - ruby/neo4j/driver/internal/async/result_cursors_holder.rb
298
299
  - ruby/neo4j/driver/internal/async/unmanaged_transaction.rb
299
300
  - ruby/neo4j/driver/internal/bookmark_holder.rb
@@ -495,9 +496,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
495
496
  version: '3.1'
496
497
  required_rubygems_version: !ruby/object:Gem::Requirement
497
498
  requirements:
498
- - - ">"
499
+ - - ">="
499
500
  - !ruby/object:Gem::Version
500
- version: 1.3.1
501
+ version: '0'
501
502
  requirements: []
502
503
  rubygems_version: 3.3.7
503
504
  signing_key:
@@ -1,25 +0,0 @@
1
- module Neo4j::Driver
2
- module Internal
3
- module Async
4
- module Pool
5
- class Controller < ::Async::Pool::Controller
6
- def initialize(constructor, limit: nil, concurrency: nil, acquisition_timeout: nil)
7
- super(constructor, limit: limit, concurrency: concurrency)
8
- @acquisition_timeout = acquisition_timeout
9
- end
10
-
11
- def wait_for_resource
12
- case @acquisition_timeout
13
- when nil
14
- super
15
- when 0
16
- available_resource or raise ::Async::TimeoutError
17
- else
18
- ::Async::Task.current.with_timeout(@acquisition_timeout) { super }
19
- end
20
- end
21
- end
22
- end
23
- end
24
- end
25
- end