neo4j-ruby-driver 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f25d2880441e748a0152d2f23afa956891bde3fd90e9c15886e21784ef0da61b
4
- data.tar.gz: 82edb2e592d1fd45f895290d49f5f7d6533193e2406d7eadae89d0344082f986
3
+ metadata.gz: 7c7d38011d191d0e26b26b02e6b147672b27806cd66d9ebb416d326bc8ed0406
4
+ data.tar.gz: 8bef825331172211356c41ba82a7b5d5c927f939d6e0a716fb6a7f0a18cfb947
5
5
  SHA512:
6
- metadata.gz: 29f37f4671b277a5b276f43bd4549a998f0ca17fbd80cfd41128d98e84fa9d64d594cfd271600e27f5fa9d20d0f33dab08c7c378790921143d5a0cf6441a9d2f
7
- data.tar.gz: d2012cb64c0336afbfdf7e15b18f38295f35f1d4c88da068ce73abf8743bd672a800f984962040c70c9f6c64b65bbfc5d3e09a5eb881c60e5c714894ee019d2e
6
+ metadata.gz: 2ceec98de33377a4dea166d894ba5c6179ff7510744c6efbaa07fbb5dfbd237c0b08278587f9ebf410f601a41e006d395cbcc3f0ebd9114439348bc24bab25d3
7
+ data.tar.gz: 16c1bb6ba7b910c86f8dc605980c393a8a4f10e0fa57eeeeb109b6fea25efaacb5125f14518666960fc0050ea82a3a64d2c8bd260db79a084522af4a701fc0f4
@@ -3,10 +3,35 @@
3
3
  module Bolt
4
4
  module Config
5
5
  extend Bolt::Library
6
+ typedef :int32_t, :bolt_scheme
7
+ typedef :int32_t, :bolt_transport
8
+
6
9
  attach_function :create, :BoltConfig_create, [], :auto_pointer
7
10
  attach_function :destroy, :BoltConfig_destroy, [:pointer], :void
11
+ attach_function :get_scheme, :BoltConfig_get_scheme, [:pointer], :bolt_scheme
12
+ attach_function :set_scheme, :BoltConfig_set_scheme, %i[pointer bolt_scheme], :int32_t
13
+ attach_function :get_transport, :BoltConfig_get_transport, [:pointer], :bolt_transport
14
+ attach_function :set_transport, :BoltConfig_set_transport, %i[pointer bolt_transport], :int32_t
15
+ attach_function :get_trust, :BoltConfig_get_trust, [:pointer], :pointer
16
+ attach_function :set_trust, :BoltConfig_set_trust, %i[pointer pointer], :int32_t
17
+ attach_function :get_user_agent, :BoltConfig_get_user_agent, [:pointer], :string
18
+ attach_function :set_user_agent, :BoltConfig_set_user_agent, %i[pointer string], :int32
19
+ attach_function :get_routing_context, :BoltConfig_get_routing_context, [:pointer], :pointer
20
+ attach_function :set_routing_context, :BoltConfig_set_routing_context, %i[pointer pointer], :int32_t
21
+ attach_function :get_address_resolver, :BoltConfig_get_address_resolver, [:pointer], :pointer
22
+ attach_function :set_address_resolver, :BoltConfig_set_address_resolver, %i[pointer pointer], :int32_t
8
23
  attach_function :get_log, :BoltConfig_get_log, [:pointer], :pointer
9
24
  attach_function :set_log, :BoltConfig_set_log, %i[pointer pointer], :int32
10
- attach_function :set_user_agent, :BoltConfig_set_user_agent, %i[pointer string], :int32
25
+ attach_function :get_max_pool_size, :BoltConfig_get_max_pool_size, [:pointer], :int32_t
26
+ attach_function :set_max_pool_size, :BoltConfig_set_max_pool_size, %i[pointer int32_t], :int32_t
27
+ attach_function :get_max_connection_life_time, :BoltConfig_get_max_connection_life_time, [:pointer], :int32_t
28
+ attach_function :set_max_connection_life_time, :BoltConfig_set_max_connection_life_time, %i[pointer int32_t],
29
+ :int32_t
30
+ attach_function :get_max_connection_acquisition_time, :BoltConfig_get_max_connection_acquisition_time, [:pointer],
31
+ :int32_t
32
+ attach_function :set_max_connection_acquisition_time, :BoltConfig_set_max_connection_acquisition_time,
33
+ %i[pointer int32_t], :int32_t
34
+ attach_function :get_socket_options, :BoltConfig_get_socket_options, [:pointer], :pointer
35
+ attach_function :set_socket_options, :BoltConfig_set_socket_options, %i[pointer pointer], :int32_t
11
36
  end
12
37
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bolt
4
+ module SocketOptions
5
+ extend Bolt::Library
6
+
7
+ attach_function :create, :BoltSocketOptions_create, [], :auto_pointer
8
+ attach_function :destroy, :BoltSocketOptions_destroy, [:pointer], :void
9
+ attach_function :get_connect_timeout, :BoltSocketOptions_get_connect_timeout, [:pointer], :int32_t
10
+ attach_function :set_connect_timeout, :BoltSocketOptions_set_connect_timeout, %i[pointer int32_t], :int32_t
11
+ attach_function :get_keep_alive, :BoltSocketOptions_get_keep_alive, [:pointer], :int32_t
12
+ attach_function :set_keep_alive, :BoltSocketOptions_set_keep_alive, %i[pointer int32_t], :int32_t
13
+ end
14
+ end
@@ -19,6 +19,8 @@ if RUBY_PLATFORM.match?(/java/)
19
19
  module V3
20
20
  end
21
21
  end
22
+ module Retry
23
+ end
22
24
  module Summary
23
25
  end
24
26
  module Util
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Neo4j
4
4
  module Driver
5
- class Config
5
+ class Config < Hash
6
6
  class TrustStrategy
7
7
  class << self
8
8
  def trust_all_certificates; end
@@ -14,9 +14,9 @@ module Neo4j
14
14
 
15
15
  auto_closable :driver
16
16
 
17
- def driver(uri, auth_token = Neo4j::Driver::AuthTokens.none, config = {})
17
+ def driver(uri, auth_token = Neo4j::Driver::AuthTokens.none, config = nil)
18
18
  raise Exceptions::AuthenticationException, 'Unsupported authentication token' unless auth_token
19
- # config ||= Config.default_config
19
+ config ||= Config.default_config
20
20
  # routing_settings = config.routing_settings
21
21
  # retry_settings = config.retry_settings
22
22
  routing_settings = nil
@@ -10,8 +10,9 @@ module Neo4j
10
10
  attr_reader :protocol
11
11
  attr_reader :bolt_connection
12
12
 
13
- def initialize(connector, mode)
13
+ def initialize(connector, mode, config)
14
14
  @connector = connector
15
+ @config = config
15
16
  @bolt_connection = with_status { |status| Bolt::Connector.acquire(@connector, mode, status) }
16
17
 
17
18
  # @protocol = Messaging::BoltProtocol.for_version(Bolt::Connection.server(bolt_connection).first)
@@ -6,12 +6,13 @@ module Neo4j
6
6
  class DirectConnectionProvider
7
7
  include ErrorHandling
8
8
 
9
- def initialize(connector)
9
+ def initialize(connector, config)
10
10
  @connector = connector
11
+ @config = config
11
12
  end
12
13
 
13
14
  def acquire_connection(mode)
14
- Async::DirectConnection.new(@connector, mode)
15
+ Async::DirectConnection.new(@connector, mode, @config)
15
16
  end
16
17
 
17
18
  def verify_connectivity
@@ -13,7 +13,8 @@ module Neo4j
13
13
  def new_instance(uri, auth_token, routing_settings, retry_settings, config)
14
14
  uri = URI(uri)
15
15
  connector, logger = create_connector(uri, auth_token, config)
16
- create_driver(uri.scheme, connector, logger, routing_settings).tap(&:verify_connectivity)
16
+ retry_logic = Retry::ExponentialBackoffRetryLogic.new(config[:max_transaction_retry_time], config[:logger])
17
+ create_driver(uri.scheme, connector, logger, routing_settings, retry_logic, config).tap(&:verify_connectivity)
17
18
  end
18
19
 
19
20
  private
@@ -22,19 +23,37 @@ module Neo4j
22
23
  address = Bolt::Address.create(host(uri).gsub(/^\[(.*)\]$/, '\\1'), port(uri).to_s)
23
24
  bolt_config = bolt_config(config)
24
25
  logger = InternalLogger.register(bolt_config, config[:logger])
26
+ set_socket_options(bolt_config, config)
25
27
  [Bolt::Connector.create(address, auth_token, bolt_config), logger]
26
28
  end
27
29
 
28
30
  def bolt_config(config)
29
31
  bolt_config = Bolt::Config.create
30
32
  config.each do |key, value|
31
- # case key
32
- # end
33
+ case key
34
+ when :max_connection_pool_size
35
+ check_error Bolt::Config.set_max_pool_size(bolt_config, value)
36
+ when :max_connection_life_time
37
+ check_error Bolt::Config.set_max_connection_life_time(bolt_config, value)
38
+ when :connection_acquisition_timeout
39
+ check_error Bolt::Config.set_max_connection_acquisition_time(bolt_config, value)
40
+ end
33
41
  end
34
42
  check_error Bolt::Config.set_user_agent(bolt_config, 'seabolt-cmake/1.7')
35
43
  bolt_config
36
44
  end
37
45
 
46
+ def set_socket_options(bolt_config, config)
47
+ socket_options = nil
48
+ config.each do |key, value|
49
+ case key
50
+ when :connection_timeout
51
+ check_error Bolt::SocketOptions.set_connect_timeout(socket_options ||= Bolt::SocketOptions.create, value)
52
+ end
53
+ end
54
+ check_error Bolt::Config.set_socket_options(bolt_config, socket_options) if socket_options
55
+ end
56
+
38
57
  def host(uri)
39
58
  uri.host.tap { |host| raise ArgumentError, "Invalid address format `#{uri}`" unless host }
40
59
  end
@@ -44,12 +63,12 @@ module Neo4j
44
63
  DEFAULT_PORT
45
64
  end
46
65
 
47
- def create_driver(scheme, connector, logger, routing_settings)
66
+ def create_driver(scheme, connector, logger, routing_settings, retry_logic, config)
48
67
  case scheme
49
68
  when BOLT_URI_SCHEME
50
69
  # assert_no_routing_context( uri, routing_settings )
51
70
  # return createDirectDriver( securityPlan, address, connectionPool, retryLogic, metrics, config );
52
- create_direct_driver(connector, logger)
71
+ create_direct_driver(connector, logger, retry_logic, config)
53
72
  when BOLT_ROUTING_URI_SCHEME, NEO4J_URI_SCHEME
54
73
  # create_routing_driver( security_plan, address, connection_ool, eventExecutorGroup, routingSettings, retryLogic, metrics, config );
55
74
  else
@@ -57,9 +76,9 @@ module Neo4j
57
76
  end
58
77
  end
59
78
 
60
- def create_direct_driver(connector, logger)
61
- connection_provider = DirectConnectionProvider.new(connector)
62
- session_factory = create_session_factory(connection_provider)
79
+ def create_direct_driver(connector, logger, retry_logic, config)
80
+ connection_provider = DirectConnectionProvider.new(connector, config)
81
+ session_factory = create_session_factory(connection_provider, retry_logic, config)
63
82
  InternalDriver.new(session_factory, logger)
64
83
  end
65
84
 
@@ -15,6 +15,13 @@ module Neo4j
15
15
  # Connection refused
16
16
  when Bolt::Error::BOLT_CONNECTION_REFUSED
17
17
  throw Exceptions::ServiceUnavailableException.new(error_code, 'unable to acquire connection')
18
+ # Connection pool is full
19
+ when Bolt::Error::BOLT_POOL_FULL
20
+ throw Exceptions::ClientException.new(
21
+ error_code,
22
+ 'Unable to acquire connection from the pool within configured maximum time of ' \
23
+ "#{@config[:connection_acquisition_timeout] * 1000}ms"
24
+ )
18
25
  # Error set in connection
19
26
  when Bolt::Error::BOLT_CONNECTION_HAS_MORE_INFO, Bolt::Error::BOLT_STATUS_SET
20
27
  status = Bolt::Connection.status(bolt_connection)
@@ -37,6 +44,21 @@ module Neo4j
37
44
  check_status(status)
38
45
  end
39
46
 
47
+ def new_neo4j_error(code:, message:)
48
+ case code.split('.')[1]
49
+ when 'ClientError'
50
+ if code.casecmp('Neo.ClientError.Security.Unauthorized').zero?
51
+ Exceptions::AuthenticationException
52
+ else
53
+ Exceptions::ClientException
54
+ end
55
+ when 'TransientError'
56
+ Exceptions::TransientException
57
+ else
58
+ Exceptions::DatabaseException
59
+ end.new(code, message)
60
+ end
61
+
40
62
  private
41
63
 
42
64
  def throw(error)
@@ -5,8 +5,6 @@ module Neo4j
5
5
  module Internal
6
6
  module Handlers
7
7
  class PullAllResponseHandler < ResponseHandler
8
- include ErrorHandling
9
-
10
8
  delegate :bolt_connection, to: :connection
11
9
  delegate :statement_keys, to: :run_handler
12
10
  attr_reader :connection
@@ -5,6 +5,8 @@ module Neo4j
5
5
  module Internal
6
6
  module Handlers
7
7
  class ResponseHandler
8
+ include ErrorHandling
9
+
8
10
  delegate :bolt_connection, to: :connection
9
11
  attr_reader :connection, :failure
10
12
  attr_accessor :request, :previous
@@ -33,7 +35,7 @@ module Neo4j
33
35
  else
34
36
  return if previous&.failure
35
37
  @failure = Value::ValueAdapter.to_ruby(Bolt::Connection.failure(bolt_connection))
36
- raise Exceptions::ClientException.new(@failure[:code], @failure[:message])
38
+ raise new_neo4j_error(@failure)
37
39
  end
38
40
  end
39
41
 
@@ -15,12 +15,7 @@ module Neo4j
15
15
  @open = Concurrent::AtomicBoolean.new(true)
16
16
  @connection_provider = connection_provider
17
17
  @mode = mode
18
- # @retry_logic = retry_logic
19
- @retry_logic = Class.new do
20
- def retry
21
- yield
22
- end
23
- end.new
18
+ @retry_logic = retry_logic
24
19
  end
25
20
 
26
21
  def run(statement, parameters = {}, config = nil)
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Internal
6
+ module Retry
7
+ class ExponentialBackoffRetryLogic
8
+ DEFAULT_MAX_RETRY_TIME = 30
9
+ INITIAL_RETRY_DELAY = 1
10
+ RETRY_DELAY_MULTIPLIER = 2.0
11
+ RETRY_DELAY_JITTER_FACTOR = 0.2
12
+
13
+ def initialize(max_retry_time = nil, logger = nil)
14
+ @max_retry_time = max_retry_time || DEFAULT_MAX_RETRY_TIME
15
+ @log = logger
16
+ end
17
+
18
+ def retry
19
+ next_delay = INITIAL_RETRY_DELAY
20
+ start_time = nil
21
+ errors = nil
22
+ loop do
23
+ return yield
24
+ rescue Exceptions::Neo4jException => error
25
+ if can_retry_on?(error)
26
+ curr_time = current_time
27
+ start_time ||= curr_time
28
+ elapsed_time = curr_time - start_time
29
+ if elapsed_time < @max_retry_time
30
+ delay_with_jitter = compute_delay_with_jitter(next_delay)
31
+ @log&.warn("Transaction failed and will be retried in #{delay_with_jitter}ms", error)
32
+ sleep(delay_with_jitter) # verify time units
33
+ next_delay *= RETRY_DELAY_MULTIPLIER
34
+ (errors ||= []) << error
35
+ next
36
+ end
37
+ end
38
+ add_suppressed(error, errors)
39
+ raise error
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def can_retry_on?(error)
46
+ error.is_a?(Exceptions::SessionExpiredException) ||
47
+ error.is_a?(Exceptions::ServiceUnavailableException) ||
48
+ transient_error?(error)
49
+ end
50
+
51
+ def transient_error?(error)
52
+ # Retries should not happen when transaction was explicitly terminated by the user.
53
+ # Termination of transaction might result in two different error codes depending on where it was
54
+ # terminated. These are really client errors but classification on the server is not entirely correct and
55
+ # they are classified as transient.
56
+ error.is_a?(Exceptions::TransientException) &&
57
+ !%w[Neo.TransientError.Transaction.Terminated Neo.TransientError.Transaction.LockClientStopped]
58
+ .include?(error.code)
59
+ end
60
+
61
+ def compute_delay_with_jitter(delay)
62
+ jitter = delay * RETRY_DELAY_JITTER_FACTOR
63
+ min = delay - jitter
64
+ max = delay + jitter
65
+ @rand ||= Random.new
66
+ @rand.rand(min..max)
67
+ end
68
+
69
+ def current_time
70
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
71
+ end
72
+
73
+ def add_suppressed(error, suppressed_errors)
74
+ suppressed_errors&.reject(&error.method(:equal?))&.each(&error.method(:add_suppressed))
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Neo4j
4
4
  module Driver
5
- VERSION = '0.1.9'
5
+ VERSION = '0.1.10'
6
6
  end
7
7
  end
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: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Heinrich Klobuczek
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-28 00:00:00.000000000 Z
11
+ date: 2019-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -239,11 +239,11 @@ files:
239
239
  - ffi/bolt/lifecycle.rb
240
240
  - ffi/bolt/list.rb
241
241
  - ffi/bolt/log.rb
242
+ - ffi/bolt/socket_options.rb
242
243
  - ffi/bolt/status.rb
243
244
  - ffi/bolt/string.rb
244
245
  - ffi/bolt/structure.rb
245
246
  - ffi/bolt/value.rb
246
- - ffi/bolt/values_private.rb
247
247
  - ffi/neo4j/driver.rb
248
248
  - ffi/neo4j/driver/access_mode.rb
249
249
  - ffi/neo4j/driver/auth_tokens.rb
@@ -270,6 +270,7 @@ files:
270
270
  - ffi/neo4j/driver/internal/messaging/v2/bolt_protocol_v2.rb
271
271
  - ffi/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb
272
272
  - ffi/neo4j/driver/internal/network_session.rb
273
+ - ffi/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb
273
274
  - ffi/neo4j/driver/internal/session_factory_impl.rb
274
275
  - ffi/neo4j/driver/internal/summary/internal_result_summary.rb
275
276
  - ffi/neo4j/driver/internal/summary/internal_server_info.rb
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bolt
4
- module ValuesPrivate
5
- extend FFI::Library
6
-
7
- typedef :pointer, :bolt_value
8
- # typedef BoltData, :bolt_data
9
- # typedef BoltExtendedValue, :bolt_extended_value
10
- #
11
- # class BoltValue < FFI::Struct
12
- # layout :type, :int16,
13
- # :subtype, :int16,
14
- # :size, :int16,
15
- # :data_size, :uint64,
16
- # :data, :bolt_data
17
- # end
18
- #
19
- # class BoltData < FFI::Union
20
- # layout :as_char, [:char, 16],
21
- # :as_uint32, [:uint32, 4],
22
- # :as_int8, [:int8_t, 16],
23
- # :as_int16, [:int16, 8],
24
- # :as_int32, [:int32, 4],
25
- # :as_int64, [:int64, 2],
26
- # :as_double, [:double, 2],
27
- # :extended, :bolt_extended_value
28
- # end
29
-
30
- class BoltExtendedValue < FFI::Union
31
- layout :as_ptr, :pointer,
32
- :as_char, :string,
33
- :as_value, :bolt_value
34
- end
35
- end
36
- end