neo4j-ruby-driver 1.7.5 → 4.4.0.alpha.2

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 (339) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -42
  3. data/lib/loader.rb +5 -3
  4. data/lib/neo4j/driver/auto_closable.rb +2 -2
  5. data/lib/neo4j/driver/exceptions/authentication_exception.rb +6 -1
  6. data/lib/neo4j/driver/exceptions/authorization_expired_exception.rb +14 -0
  7. data/lib/neo4j/driver/{types/bytes.rb → exceptions/certificate_exception.rb} +2 -2
  8. data/lib/neo4j/driver/exceptions/client_exception.rb +3 -0
  9. data/lib/neo4j/driver/exceptions/connection_read_timeout_exception.rb +14 -0
  10. data/lib/neo4j/driver/exceptions/database_exception.rb +3 -0
  11. data/lib/neo4j/driver/exceptions/discovery_exception.rb +16 -0
  12. data/lib/neo4j/driver/exceptions/fatal_discovery_exception.rb +13 -0
  13. data/lib/neo4j/driver/exceptions/protocol_exception.rb +7 -0
  14. data/lib/neo4j/driver/exceptions/result_consumed_exception.rb +13 -0
  15. data/lib/neo4j/driver/exceptions/security_exception.rb +5 -1
  16. data/lib/neo4j/driver/exceptions/service_unavailable_exception.rb +2 -0
  17. data/lib/neo4j/driver/exceptions/session_expired_exception.rb +4 -0
  18. data/lib/neo4j/driver/exceptions/token_expired_exception.rb +15 -0
  19. data/lib/neo4j/driver/exceptions/transaction_nesting_exception.rb +11 -0
  20. data/lib/neo4j/driver/exceptions/transient_exception.rb +3 -0
  21. data/lib/neo4j/driver/exceptions/untrusted_server_exception.rb +1 -0
  22. data/lib/neo4j/driver/exceptions/value/lossy_coercion.rb +15 -0
  23. data/lib/neo4j/driver/exceptions/value/not_multi_valued.rb +13 -0
  24. data/lib/neo4j/driver/exceptions/value/uncoercible.rb +15 -0
  25. data/lib/neo4j/driver/exceptions/value/unsizable.rb +12 -0
  26. data/lib/neo4j/driver/exceptions/value/value_exception.rb +12 -0
  27. data/lib/neo4j/driver/internal/bolt_server_address.rb +97 -0
  28. data/lib/neo4j/driver/internal/duration_normalizer.rb +1 -1
  29. data/lib/neo4j/driver/internal/validator.rb +5 -4
  30. data/{ffi/neo4j/driver/summary/statement_type.rb → lib/neo4j/driver/summary/query_type.rb} +1 -3
  31. data/lib/neo4j/driver/synchronizable.rb +23 -0
  32. data/lib/neo4j_ruby_driver.rb +5 -10
  33. data/{ffi → ruby}/neo4j/driver/access_mode.rb +2 -2
  34. data/ruby/neo4j/driver/auth_tokens.rb +34 -0
  35. data/ruby/neo4j/driver/bookmark.rb +21 -0
  36. data/ruby/neo4j/driver/config.rb +91 -0
  37. data/ruby/neo4j/driver/graph_database.rb +140 -0
  38. data/ruby/neo4j/driver/internal/async/connection/bolt_protocol_util.rb +51 -0
  39. data/ruby/neo4j/driver/internal/async/connection/bootstrap_factory.rb +22 -0
  40. data/ruby/neo4j/driver/internal/async/connection/channel_attributes.rb +31 -0
  41. data/ruby/neo4j/driver/internal/async/connection/channel_connected_listener.rb +32 -0
  42. data/ruby/neo4j/driver/internal/async/connection/channel_connector_impl.rb +77 -0
  43. data/ruby/neo4j/driver/internal/async/connection/channel_pipeline_builder_impl.rb +22 -0
  44. data/ruby/neo4j/driver/internal/async/connection/direct_connection.rb +30 -0
  45. data/ruby/neo4j/driver/internal/async/connection/event_loop_group_factory.rb +83 -0
  46. data/ruby/neo4j/driver/internal/async/connection/handshake_completed_listener.rb +27 -0
  47. data/ruby/neo4j/driver/internal/async/connection/handshake_handler.rb +113 -0
  48. data/ruby/neo4j/driver/internal/async/connection/netty_channel_initializer.rb +57 -0
  49. data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver.rb +26 -0
  50. data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver_group.rb +19 -0
  51. data/ruby/neo4j/driver/internal/async/connection/routing_connection.rb +36 -0
  52. data/ruby/neo4j/driver/internal/async/connection/stream.rb +12 -0
  53. data/ruby/neo4j/driver/internal/async/connection/stream_reader.rb +16 -0
  54. data/ruby/neo4j/driver/internal/async/connection_context.rb +10 -0
  55. data/ruby/neo4j/driver/internal/async/immutable_connection_context.rb +24 -0
  56. data/ruby/neo4j/driver/internal/async/inbound/byte_buf_input.rb +30 -0
  57. data/ruby/neo4j/driver/internal/async/inbound/channel_error_handler.rb +77 -0
  58. data/ruby/neo4j/driver/internal/async/inbound/chunk_decoder.rb +41 -0
  59. data/ruby/neo4j/driver/internal/async/inbound/connect_timeout_handler.rb +32 -0
  60. data/ruby/neo4j/driver/internal/async/inbound/connection_read_timeout_handler.rb +17 -0
  61. data/ruby/neo4j/driver/internal/async/inbound/inbound_message_dispatcher.rb +172 -0
  62. data/ruby/neo4j/driver/internal/async/inbound/inbound_message_handler.rb +42 -0
  63. data/ruby/neo4j/driver/internal/async/inbound/message_decoder.rb +51 -0
  64. data/ruby/neo4j/driver/internal/async/internal_async_session.rb +98 -0
  65. data/ruby/neo4j/driver/internal/async/internal_async_transaction.rb +13 -0
  66. data/ruby/neo4j/driver/internal/async/leak_logging_network_session.rb +34 -0
  67. data/ruby/neo4j/driver/internal/async/network_connection.rb +196 -0
  68. data/ruby/neo4j/driver/internal/async/network_session.rb +152 -0
  69. data/ruby/neo4j/driver/internal/async/outbound/chunk_aware_byte_buf_output.rb +110 -0
  70. data/ruby/neo4j/driver/internal/async/outbound/outbound_message_handler.rb +39 -0
  71. data/ruby/neo4j/driver/internal/async/pool/channel.rb +63 -0
  72. data/ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb +149 -0
  73. data/ruby/neo4j/driver/internal/async/pool/controller.rb +25 -0
  74. data/ruby/neo4j/driver/internal/async/pool/netty_channel_health_checker.rb +87 -0
  75. data/ruby/neo4j/driver/internal/async/pool/netty_channel_pool.rb +52 -0
  76. data/ruby/neo4j/driver/internal/async/pool/netty_channel_tracker.rb +137 -0
  77. data/ruby/neo4j/driver/internal/async/pool/network_connection_factory.rb +21 -0
  78. data/ruby/neo4j/driver/internal/async/pool/pool_settings.rb +34 -0
  79. data/ruby/neo4j/driver/internal/async/result_cursors_holder.rb +17 -0
  80. data/ruby/neo4j/driver/internal/async/unmanaged_transaction.rb +214 -0
  81. data/ruby/neo4j/driver/internal/bookmark_holder.rb +9 -0
  82. data/ruby/neo4j/driver/internal/cluster/cluster_composition.rb +58 -0
  83. data/ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb +14 -0
  84. data/ruby/neo4j/driver/internal/cluster/cluster_routing_table.rb +139 -0
  85. data/ruby/neo4j/driver/internal/cluster/identity_resolver.rb +13 -0
  86. data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb +68 -0
  87. data/ruby/neo4j/driver/internal/cluster/loadbalancing/load_balancer.rb +159 -0
  88. data/ruby/neo4j/driver/internal/cluster/loadbalancing/round_robin_array_index.rb +13 -0
  89. data/ruby/neo4j/driver/internal/cluster/multi_databases_routing_procedure_runner.rb +34 -0
  90. data/ruby/neo4j/driver/internal/cluster/rediscovery_impl.rb +238 -0
  91. data/ruby/neo4j/driver/internal/cluster/route_message_routing_procedure_runner.rb +43 -0
  92. data/ruby/neo4j/driver/internal/cluster/routing_context.rb +77 -0
  93. data/ruby/neo4j/driver/internal/cluster/routing_procedure_cluster_composition_provider.rb +64 -0
  94. data/ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb +19 -0
  95. data/ruby/neo4j/driver/internal/cluster/routing_settings.rb +24 -0
  96. data/ruby/neo4j/driver/internal/cluster/routing_table_handler_impl.rb +116 -0
  97. data/ruby/neo4j/driver/internal/cluster/routing_table_registry_impl.rb +140 -0
  98. data/ruby/neo4j/driver/internal/cluster/single_database_routing_procedure_runner.rb +76 -0
  99. data/ruby/neo4j/driver/internal/connection_settings.rb +16 -0
  100. data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +76 -0
  101. data/ruby/neo4j/driver/internal/cursor/async_result_cursor_only_factory.rb +29 -0
  102. data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +59 -0
  103. data/ruby/neo4j/driver/internal/cursor/result_cursor_factory_impl.rb +29 -0
  104. data/ruby/neo4j/driver/internal/cursor/rx_result_cursor_impl.rb +110 -0
  105. data/ruby/neo4j/driver/internal/database_name.rb +12 -0
  106. data/ruby/neo4j/driver/internal/database_name_util.rb +37 -0
  107. data/ruby/neo4j/driver/internal/default_bookmark_holder.rb +15 -0
  108. data/ruby/neo4j/driver/internal/default_domain_name_resolver.rb +11 -0
  109. data/ruby/neo4j/driver/internal/direct_connection_provider.rb +40 -0
  110. data/ruby/neo4j/driver/internal/driver_factory.rb +127 -0
  111. data/ruby/neo4j/driver/internal/handlers/begin_tx_response_handler.rb +20 -0
  112. data/ruby/neo4j/driver/internal/handlers/channel_releasing_reset_response_handler.rb +29 -0
  113. data/ruby/neo4j/driver/internal/handlers/commit_tx_response_handler.rb +25 -0
  114. data/ruby/neo4j/driver/internal/handlers/hello_response_handler.rb +65 -0
  115. data/ruby/neo4j/driver/internal/handlers/init_response_handler.rb +34 -0
  116. data/ruby/neo4j/driver/internal/handlers/legacy_pull_all_response_handler.rb +228 -0
  117. data/ruby/neo4j/driver/internal/handlers/no_op_response_handler.rb +16 -0
  118. data/ruby/neo4j/driver/internal/handlers/ping_response_handler.rb +29 -0
  119. data/ruby/neo4j/driver/internal/handlers/pull_handlers.rb +32 -0
  120. data/ruby/neo4j/driver/internal/handlers/pulln/auto_pull_response_handler.rb +174 -0
  121. data/ruby/neo4j/driver/internal/handlers/pulln/basic_pull_response_handler.rb +288 -0
  122. data/ruby/neo4j/driver/internal/handlers/pulln/fetch_size_util.rb +20 -0
  123. data/ruby/neo4j/driver/internal/handlers/reset_response_handler.rb +34 -0
  124. data/ruby/neo4j/driver/internal/handlers/rollback_tx_response_handler.rb +19 -0
  125. data/ruby/neo4j/driver/internal/handlers/route_message_response_handler.rb +21 -0
  126. data/ruby/neo4j/driver/internal/handlers/routing_response_handler.rb +70 -0
  127. data/ruby/neo4j/driver/internal/handlers/run_response_handler.rb +37 -0
  128. data/ruby/neo4j/driver/internal/handlers/session_pull_response_completion_listener.rb +34 -0
  129. data/ruby/neo4j/driver/internal/handlers/transaction_pull_response_completion_listener.rb +20 -0
  130. data/ruby/neo4j/driver/internal/impersonation_util.rb +22 -0
  131. data/ruby/neo4j/driver/internal/internal_bookmark.rb +38 -0
  132. data/ruby/neo4j/driver/internal/internal_database_name.rb +11 -0
  133. data/ruby/neo4j/driver/internal/internal_driver.rb +78 -0
  134. data/ruby/neo4j/driver/internal/internal_entity.rb +22 -0
  135. data/ruby/neo4j/driver/internal/internal_node.rb +21 -0
  136. data/ruby/neo4j/driver/internal/internal_pair.rb +9 -0
  137. data/ruby/neo4j/driver/internal/internal_path.rb +35 -0
  138. data/ruby/neo4j/driver/internal/internal_point2_d.rb +9 -0
  139. data/ruby/neo4j/driver/internal/internal_point3_d.rb +6 -0
  140. data/{ffi → ruby}/neo4j/driver/internal/internal_record.rb +2 -1
  141. data/ruby/neo4j/driver/internal/internal_relationship.rb +26 -0
  142. data/ruby/neo4j/driver/internal/internal_result.rb +60 -0
  143. data/ruby/neo4j/driver/internal/internal_session.rb +81 -0
  144. data/ruby/neo4j/driver/internal/internal_transaction.rb +48 -0
  145. data/ruby/neo4j/driver/internal/logging/channel_activity_logger.rb +29 -0
  146. data/ruby/neo4j/driver/internal/logging/channel_error_logger.rb +17 -0
  147. data/ruby/neo4j/driver/internal/logging/prefixed_logger.rb +19 -0
  148. data/ruby/neo4j/driver/internal/logging/reformatted_logger.rb +17 -0
  149. data/ruby/neo4j/driver/internal/messaging/abstract_message_writer.rb +23 -0
  150. data/ruby/neo4j/driver/internal/messaging/bolt_protocol.rb +30 -0
  151. data/ruby/neo4j/driver/internal/messaging/bolt_protocol_version.rb +46 -0
  152. data/ruby/neo4j/driver/internal/messaging/common/common_message_reader.rb +51 -0
  153. data/ruby/neo4j/driver/internal/messaging/common/common_value.rb +31 -0
  154. data/ruby/neo4j/driver/internal/messaging/common/common_value_packer.rb +101 -0
  155. data/ruby/neo4j/driver/internal/messaging/common/common_value_unpacker.rb +234 -0
  156. data/ruby/neo4j/driver/internal/messaging/encode/begin_message_encoder.rb +15 -0
  157. data/ruby/neo4j/driver/internal/messaging/encode/commit_message_encoder.rb +14 -0
  158. data/ruby/neo4j/driver/internal/messaging/encode/discard_all_message_encoder.rb +14 -0
  159. data/ruby/neo4j/driver/internal/messaging/encode/discard_message_encoder.rb +15 -0
  160. data/ruby/neo4j/driver/internal/messaging/encode/goodbye_message_encoder.rb +14 -0
  161. data/ruby/neo4j/driver/internal/messaging/encode/hello_message_encoder.rb +15 -0
  162. data/ruby/neo4j/driver/internal/messaging/encode/init_message_encoder.rb +16 -0
  163. data/ruby/neo4j/driver/internal/messaging/encode/pull_all_message_encoder.rb +14 -0
  164. data/ruby/neo4j/driver/internal/messaging/encode/pull_message_encoder.rb +15 -0
  165. data/ruby/neo4j/driver/internal/messaging/encode/reset_message_encoder.rb +14 -0
  166. data/ruby/neo4j/driver/internal/messaging/encode/rollback_message_encoder.rb +14 -0
  167. data/ruby/neo4j/driver/internal/messaging/encode/route_message_encoder.rb +18 -0
  168. data/ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb +27 -0
  169. data/ruby/neo4j/driver/internal/messaging/encode/run_message_encoder.rb +16 -0
  170. data/ruby/neo4j/driver/internal/messaging/encode/run_with_metadata_message_encoder.rb +17 -0
  171. data/ruby/neo4j/driver/internal/messaging/request/abstract_streaming_message.rb +22 -0
  172. data/ruby/neo4j/driver/internal/messaging/request/begin_message.rb +26 -0
  173. data/ruby/neo4j/driver/internal/messaging/request/commit_message.rb +20 -0
  174. data/ruby/neo4j/driver/internal/messaging/request/discard_all_message.rb +20 -0
  175. data/ruby/neo4j/driver/internal/messaging/request/discard_message.rb +23 -0
  176. data/ruby/neo4j/driver/internal/messaging/request/goodbye_message.rb +20 -0
  177. data/ruby/neo4j/driver/internal/messaging/request/hello_message.rb +31 -0
  178. data/ruby/neo4j/driver/internal/messaging/request/init_message.rb +19 -0
  179. data/ruby/neo4j/driver/internal/messaging/request/message_with_metadata.rb +10 -0
  180. data/ruby/neo4j/driver/internal/messaging/request/multi_database_util.rb +26 -0
  181. data/ruby/neo4j/driver/internal/messaging/request/pull_all_message.rb +23 -0
  182. data/ruby/neo4j/driver/internal/messaging/request/pull_message.rb +22 -0
  183. data/ruby/neo4j/driver/internal/messaging/request/reset_message.rb +32 -0
  184. data/ruby/neo4j/driver/internal/messaging/request/rollback_message.rb +20 -0
  185. data/ruby/neo4j/driver/internal/messaging/request/route_message.rb +33 -0
  186. data/ruby/neo4j/driver/internal/messaging/request/run_message.rb +23 -0
  187. data/ruby/neo4j/driver/internal/messaging/request/run_with_metadata_message.rb +47 -0
  188. data/ruby/neo4j/driver/internal/messaging/request/transaction_metadata_builder.rb +24 -0
  189. data/ruby/neo4j/driver/internal/messaging/response/failure_message.rb +40 -0
  190. data/ruby/neo4j/driver/internal/messaging/response/ignored_message.rb +29 -0
  191. data/ruby/neo4j/driver/internal/messaging/response/record_message.rb +33 -0
  192. data/ruby/neo4j/driver/internal/messaging/response/success_message.rb +34 -0
  193. data/ruby/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +79 -0
  194. data/ruby/neo4j/driver/internal/messaging/v3/message_format_v3.rb +17 -0
  195. data/ruby/neo4j/driver/internal/messaging/v3/message_writer_v3.rb +27 -0
  196. data/ruby/neo4j/driver/internal/messaging/v4/bolt_protocol_v4.rb +29 -0
  197. data/ruby/neo4j/driver/internal/messaging/v4/message_format_v4.rb +17 -0
  198. data/ruby/neo4j/driver/internal/messaging/v4/message_writer_v4.rb +28 -0
  199. data/ruby/neo4j/driver/internal/messaging/v41/bolt_protocol_v41.rb +25 -0
  200. data/ruby/neo4j/driver/internal/messaging/v42/bolt_protocol_v42.rb +13 -0
  201. data/ruby/neo4j/driver/internal/messaging/v43/bolt_protocol_v43.rb +19 -0
  202. data/ruby/neo4j/driver/internal/messaging/v43/message_format_v43.rb +18 -0
  203. data/ruby/neo4j/driver/internal/messaging/v43/message_writer_v43.rb +34 -0
  204. data/ruby/neo4j/driver/internal/messaging/v44/bolt_protocol_v44.rb +17 -0
  205. data/ruby/neo4j/driver/internal/messaging/v44/message_format_v44.rb +18 -0
  206. data/ruby/neo4j/driver/internal/messaging/v44/message_writer_v44.rb +26 -0
  207. data/ruby/neo4j/driver/internal/metrics/connection_pool_metrics_listener.rb +34 -0
  208. data/ruby/neo4j/driver/internal/metrics/internal_abstract_metrics.rb +46 -0
  209. data/ruby/neo4j/driver/internal/metrics/internal_connection_pool_metrics.rb +105 -0
  210. data/ruby/neo4j/driver/internal/metrics/internal_metrics.rb +82 -0
  211. data/ruby/neo4j/driver/internal/metrics/internal_metrics_provider.rb +18 -0
  212. data/ruby/neo4j/driver/internal/metrics/listener_event.rb +17 -0
  213. data/ruby/neo4j/driver/internal/metrics/metrics_provider.rb +24 -0
  214. data/ruby/neo4j/driver/internal/metrics/time_recorder_listener_event.rb +15 -0
  215. data/ruby/neo4j/driver/internal/packstream/byte_array_incompatible_packer.rb +12 -0
  216. data/ruby/neo4j/driver/internal/packstream/pack_input.rb +47 -0
  217. data/ruby/neo4j/driver/internal/packstream/pack_output.rb +39 -0
  218. data/ruby/neo4j/driver/internal/packstream/pack_stream.rb +326 -0
  219. data/ruby/neo4j/driver/internal/packstream/pack_type.rb +17 -0
  220. data/ruby/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb +151 -0
  221. data/ruby/neo4j/driver/internal/revocation_strategy.rb +19 -0
  222. data/ruby/neo4j/driver/internal/scheme.rb +32 -0
  223. data/ruby/neo4j/driver/internal/security/internal_auth_token.rb +15 -0
  224. data/ruby/neo4j/driver/internal/security/security_plan_impl.rb +92 -0
  225. data/ruby/neo4j/driver/internal/security_setting.rb +73 -0
  226. data/ruby/neo4j/driver/internal/session_factory_impl.rb +32 -0
  227. data/ruby/neo4j/driver/internal/spi/connection.rb +19 -0
  228. data/ruby/neo4j/driver/internal/spi/connection_pool.rb +9 -0
  229. data/ruby/neo4j/driver/internal/spi/response_handler.rb +23 -0
  230. data/ruby/neo4j/driver/internal/summary/internal_database_info.rb +7 -0
  231. data/ruby/neo4j/driver/internal/summary/internal_input_position.rb +11 -0
  232. data/ruby/neo4j/driver/internal/summary/internal_notification.rb +16 -0
  233. data/ruby/neo4j/driver/internal/summary/internal_plan.rb +41 -0
  234. data/ruby/neo4j/driver/internal/summary/internal_profiled_plan.rb +32 -0
  235. data/ruby/neo4j/driver/internal/summary/internal_result_summary.rb +33 -0
  236. data/ruby/neo4j/driver/internal/summary/internal_server_info.rb +6 -0
  237. data/ruby/neo4j/driver/internal/summary/internal_summary_counters.rb +18 -0
  238. data/ruby/neo4j/driver/internal/svm/netty_substitutions.rb +196 -0
  239. data/ruby/neo4j/driver/internal/svm/z_lib_substitutions.rb +21 -0
  240. data/ruby/neo4j/driver/internal/util/certificate_tool.rb +65 -0
  241. data/ruby/neo4j/driver/internal/util/clock.rb +29 -0
  242. data/ruby/neo4j/driver/internal/util/error_util.rb +104 -0
  243. data/ruby/neo4j/driver/internal/util/extract.rb +123 -0
  244. data/ruby/neo4j/driver/internal/util/format.rb +39 -0
  245. data/ruby/neo4j/driver/internal/util/futures.rb +99 -0
  246. data/ruby/neo4j/driver/internal/util/iterables.rb +35 -0
  247. data/ruby/neo4j/driver/internal/util/lock_util.rb +23 -0
  248. data/ruby/neo4j/driver/internal/util/metadata_extractor.rb +109 -0
  249. data/ruby/neo4j/driver/internal/util/mutex.rb +9 -0
  250. data/ruby/neo4j/driver/internal/util/preconditions.rb +16 -0
  251. data/ruby/neo4j/driver/internal/util/server_version.rb +60 -0
  252. data/ruby/neo4j/driver/logging1.rb +51 -0
  253. data/ruby/neo4j/driver/net/server_address1.rb +9 -0
  254. data/ruby/neo4j/driver/query.rb +48 -0
  255. data/ruby/neo4j/driver/records.rb +13 -0
  256. data/ruby/neo4j/driver/session_config.rb +15 -0
  257. data/ruby/neo4j/driver/transaction_config.rb +46 -0
  258. data/ruby/neo4j/driver/values.rb +26 -0
  259. data/{lib → ruby}/neo4j/driver/version.rb +1 -1
  260. data/ruby/neo4j/driver.rb +30 -0
  261. metadata +267 -92
  262. data/ffi/bolt/address.rb +0 -11
  263. data/ffi/bolt/address_resolver.rb +0 -12
  264. data/ffi/bolt/address_set.rb +0 -9
  265. data/ffi/bolt/auth.rb +0 -10
  266. data/ffi/bolt/auto_releasable.rb +0 -22
  267. data/ffi/bolt/boolean.rb +0 -9
  268. data/ffi/bolt/bytes.rb +0 -10
  269. data/ffi/bolt/config.rb +0 -45
  270. data/ffi/bolt/connection.rb +0 -44
  271. data/ffi/bolt/connector.rb +0 -17
  272. data/ffi/bolt/dictionary.rb +0 -15
  273. data/ffi/bolt/error.rb +0 -74
  274. data/ffi/bolt/float.rb +0 -9
  275. data/ffi/bolt/integer.rb +0 -9
  276. data/ffi/bolt/library.rb +0 -12
  277. data/ffi/bolt/lifecycle.rb +0 -9
  278. data/ffi/bolt/list.rb +0 -10
  279. data/ffi/bolt/log.rb +0 -16
  280. data/ffi/bolt/socket_options.rb +0 -14
  281. data/ffi/bolt/status.rb +0 -25
  282. data/ffi/bolt/string.rb +0 -9
  283. data/ffi/bolt/structure.rb +0 -10
  284. data/ffi/bolt/value.rb +0 -35
  285. data/ffi/neo4j/driver/auth_tokens.rb +0 -18
  286. data/ffi/neo4j/driver/config.rb +0 -40
  287. data/ffi/neo4j/driver/graph_database.rb +0 -52
  288. data/ffi/neo4j/driver/internal/async/access_mode_connection.rb +0 -19
  289. data/ffi/neo4j/driver/internal/async/direct_connection.rb +0 -106
  290. data/ffi/neo4j/driver/internal/bolt_server_address.rb +0 -18
  291. data/ffi/neo4j/driver/internal/bookmarks_holder.rb +0 -30
  292. data/ffi/neo4j/driver/internal/direct_connection_provider.rb +0 -28
  293. data/ffi/neo4j/driver/internal/driver_factory.rb +0 -126
  294. data/ffi/neo4j/driver/internal/error_handling.rb +0 -112
  295. data/ffi/neo4j/driver/internal/explicit_transaction.rb +0 -146
  296. data/ffi/neo4j/driver/internal/handlers/pull_all_response_handler.rb +0 -104
  297. data/ffi/neo4j/driver/internal/handlers/response_handler.rb +0 -49
  298. data/ffi/neo4j/driver/internal/handlers/run_response_handler.rb +0 -32
  299. data/ffi/neo4j/driver/internal/handlers/session_pull_all_response_handler.rb +0 -32
  300. data/ffi/neo4j/driver/internal/handlers/transaction_pull_all_response_handler.rb +0 -23
  301. data/ffi/neo4j/driver/internal/internal_driver.rb +0 -45
  302. data/ffi/neo4j/driver/internal/internal_logger.rb +0 -32
  303. data/ffi/neo4j/driver/internal/internal_resolver.rb +0 -31
  304. data/ffi/neo4j/driver/internal/internal_statement_result.rb +0 -52
  305. data/ffi/neo4j/driver/internal/messaging/bolt_protocol.rb +0 -24
  306. data/ffi/neo4j/driver/internal/messaging/v1/bolt_protocol_v1.rb +0 -59
  307. data/ffi/neo4j/driver/internal/messaging/v2/bolt_protocol_v2.rb +0 -16
  308. data/ffi/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +0 -63
  309. data/ffi/neo4j/driver/internal/network_session.rb +0 -129
  310. data/ffi/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb +0 -80
  311. data/ffi/neo4j/driver/internal/session_factory_impl.rb +0 -28
  312. data/ffi/neo4j/driver/internal/summary/internal_result_summary.rb +0 -67
  313. data/ffi/neo4j/driver/internal/summary/internal_server_info.rb +0 -19
  314. data/ffi/neo4j/driver/internal/summary/internal_summary_counters.rb +0 -23
  315. data/ffi/neo4j/driver/internal/util/metadata_extractor.rb +0 -15
  316. data/ffi/neo4j/driver/internal/value/base_time_value.rb +0 -22
  317. data/ffi/neo4j/driver/internal/value/date_value.rb +0 -25
  318. data/ffi/neo4j/driver/internal/value/duration_value.rb +0 -27
  319. data/ffi/neo4j/driver/internal/value/local_date_time_value.rb +0 -24
  320. data/ffi/neo4j/driver/internal/value/local_time_value.rb +0 -19
  321. data/ffi/neo4j/driver/internal/value/node_value.rb +0 -18
  322. data/ffi/neo4j/driver/internal/value/offset_time_value.rb +0 -25
  323. data/ffi/neo4j/driver/internal/value/path_value.rb +0 -41
  324. data/ffi/neo4j/driver/internal/value/point2_d_value.rb +0 -24
  325. data/ffi/neo4j/driver/internal/value/point3_d_value.rb +0 -24
  326. data/ffi/neo4j/driver/internal/value/relationship_value.rb +0 -18
  327. data/ffi/neo4j/driver/internal/value/structure_value.rb +0 -42
  328. data/ffi/neo4j/driver/internal/value/time_with_zone_id_value.rb +0 -25
  329. data/ffi/neo4j/driver/internal/value/time_with_zone_offset_value.rb +0 -28
  330. data/ffi/neo4j/driver/internal/value/unbound_relationship_value.rb +0 -18
  331. data/ffi/neo4j/driver/internal/value/value_adapter.rb +0 -101
  332. data/ffi/neo4j/driver/net/server_address.rb +0 -13
  333. data/ffi/neo4j/driver/statement.rb +0 -15
  334. data/ffi/neo4j/driver/types/entity.rb +0 -21
  335. data/ffi/neo4j/driver/types/node.rb +0 -16
  336. data/ffi/neo4j/driver/types/path.rb +0 -35
  337. data/ffi/neo4j/driver/types/relationship.rb +0 -19
  338. data/ffi/neo4j/driver.rb +0 -61
  339. data/lib/neo4j/driver/internal/ruby_signature.rb +0 -18
@@ -0,0 +1,68 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Cluster
4
+ module Loadbalancing
5
+
6
+ # Load balancing strategy that finds server with the least amount of active (checked out of the pool) connections from given readers or writers. It finds a
7
+ # start index for iteration in a round-robin fashion. This is done to prevent choosing same first address over and over when all addresses have the same amount
8
+ # of active connections.
9
+ class LeastConnectedLoadBalancingStrategy
10
+
11
+ def initialize(connection_pool, logger)
12
+ @readers_index = RoundRobinArrayIndex.new
13
+ @writers_index = RoundRobinArrayIndex.new
14
+
15
+ @connection_pool = connection_pool
16
+ @log = logger
17
+ end
18
+
19
+ def select_reader(known_readers)
20
+ select(known_readers, @readers_index, 'reader')
21
+ end
22
+
23
+ def select_writer(known_writers)
24
+ select(known_writers, @writers_index, 'writer')
25
+ end
26
+
27
+ private
28
+
29
+ def select(addresses, addresses_index, address_type)
30
+ size = addresses.size
31
+
32
+ if size == 0
33
+ @log.debug("Unable to select #{address_type}, no known addresses given")
34
+ return nil
35
+ end
36
+
37
+ # choose start index for iteration in round-robin fashion
38
+ start_index = addresses_index.next(size)
39
+ index = start_index
40
+
41
+ least_connected_address = nil
42
+ least_active_connections = java.lang.Integer::MAX_VALUE
43
+
44
+ # iterate over the array to find the least connected address
45
+ loop do
46
+ address = addresses[index]
47
+ active_connections = @connection_pool.in_use_connections(address)
48
+
49
+ if active_connections < least_active_connections
50
+ least_connected_address = address
51
+ least_active_connections = active_connections
52
+ end
53
+
54
+ # loop over to the start of the array when end is reached
55
+ index = (index == size - 1) ? 0 : index += 1
56
+
57
+ break if index != start_index
58
+ end
59
+
60
+ @log.debug("Selected #{address_type} with address: '#{least_connected_address}' and active connections: #{least_active_connections}")
61
+
62
+ least_connected_address
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,159 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Cluster
4
+ module Loadbalancing
5
+ class LoadBalancer
6
+ CONNECTION_ACQUISITION_COMPLETION_FAILURE_MESSAGE = 'Connection acquisition failed for all available addresses.'
7
+ CONNECTION_ACQUISITION_COMPLETION_EXCEPTION_MESSAGE = "Failed to obtain connection towards %s server. Known routing table is: %s"
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
+ BOLT_SERVER_ADDRESSES_EMPTY_ARRAY = []
10
+
11
+ attr_reader :routing_tables
12
+
13
+ delegate :close, to: :@connection_pool
14
+
15
+ def initialize(initial_router, settings, connection_pool, event_executor_group, logger, load_balancing_strategy, resolver, &domain_name_resolver)
16
+ clock = Util::Clock::System
17
+ @connection_pool = connection_pool
18
+ @rediscovery = create_rediscovery(event_executor_group, initial_router, resolver, settings, clock, logger, domain_name_resolver)
19
+ @routing_tables = create_routing_tables(connection_pool, @rediscovery, settings, clock, logger)
20
+ @load_balancing_strategy = load_balancing_strategy
21
+ @event_executor_group = event_executor_group
22
+ @log = logger
23
+ end
24
+
25
+ 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_future, Async::ConnectionContext::PENDING_DATABASE_NAME_EXCEPTION_SUPPLIER),
30
+ context.mode, context.impersonated_user, handler)
31
+ end
32
+ end
33
+ end
34
+
35
+ 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
45
+ end
46
+
47
+ def supports_multi_db?
48
+ begin
49
+ addresses = @rediscovery.resolve
50
+ rescue StandardError => error
51
+ return Util::Futures.failed_future(error)
52
+ end
53
+
54
+ result = Util::Futures.completed_with_null
55
+ 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
72
+ end
73
+
74
+ private
75
+
76
+ 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
81
+ end
82
+
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
+
89
+ addresses = addresses_by_mode(mode, routing_table)
90
+ address = select_address(mode, addresses)
91
+
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
99
+ end
100
+
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
118
+ end
119
+ end
120
+
121
+ def addresses_by_mode(mode, routing_table)
122
+ case mode
123
+ when READ
124
+ routing_table.readers
125
+ when WRITE
126
+ routing_table.writers
127
+ else
128
+ raise unknown_mode mode
129
+ end
130
+ end
131
+
132
+ def select_address(mode, addresses)
133
+ case mode
134
+ when READ
135
+ @load_balancing_strategy.select_reader(addresses)
136
+ when WRITE
137
+ @load_balancing_strategy.select_writer(addresses)
138
+ else
139
+ raise unknown_mode mode
140
+ end
141
+ end
142
+
143
+ 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))
145
+ end
146
+
147
+ def create_rediscovery(event_executor_group, initial_router, resolver, settings, clock, logger, domain_name_resolver)
148
+ cluster_composition_provider = RoutingProcedureClusterCompositionProvider.new(clock, settings.routing_context)
149
+ RediscoveryImpl.new(initial_router, settings, cluster_composition_provider, event_executor_group, resolver, logger, domain_name_resolver)
150
+ end
151
+
152
+ def unknown_mode(mode)
153
+ ArgumentError.new("Mode '#{mode}' is not supported")
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,13 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Cluster
4
+ module Loadbalancing
5
+ class RoundRobinArrayIndex < Concurrent::AtomicFixnum
6
+ def next(array_length)
7
+ (increment - 1) % array_length if array_length.positive?
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Cluster
4
+
5
+ # This implementation of the {@link RoutingProcedureRunner} works with multi database versions of Neo4j calling
6
+ # the procedure `dbms.routing.getRoutingTable`
7
+ class MultiDatabasesRoutingProcedureRunner < SingleDatabaseRoutingProcedureRunner
8
+ DATABASE_NAME = 'database'
9
+ MULTI_DB_GET_ROUTING_TABLE = "CALL dbms.routing.getRoutingTable($%s, $%s)" % [SingleDatabaseRoutingProcedureRunner::ROUTING_CONTEXT, DATABASE_NAME]
10
+
11
+ def initialize(context)
12
+ super(context)
13
+ end
14
+
15
+ private
16
+
17
+ def bookmark_holder(bookmark)
18
+ ReadOnlyBookmarkHolder.new(bookmark)
19
+ end
20
+
21
+ 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))
26
+ end
27
+
28
+ def connection(connection)
29
+ Async::Connection::DirectConnection.new(connection, DatabaseNameUtil::SYSTEM_DATABASE, AccessMode::READ, nil)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,238 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Cluster
4
+ class RediscoveryImpl
5
+ NO_ROUTERS_AVAILABLE = "Could not perform discovery for database '%s'. No routing server available."
6
+ RECOVERABLE_ROUTING_ERROR = "Failed to update routing table with server '%s'."
7
+ RECOVERABLE_DISCOVERY_ERROR_WITH_SERVER = "Received a recoverable discovery error with server '%s', will continue discovery with other routing servers if available. Complete failure is reported separately from this entry."
8
+ INVALID_BOOKMARK_CODE = 'Neo.ClientError.Transaction.InvalidBookmark'
9
+ INVALID_BOOKMARK_MIXTURE_CODE = 'Neo.ClientError.Transaction.InvalidBookmarkMixture'
10
+
11
+ def initialize(initial_router, settings, provider, event_executor_group, resolver, logger, domain_name_resolver)
12
+ @initial_router = initial_router
13
+ @settings = settings
14
+ @log = logger
15
+ @provider = provider
16
+ @resolver = resolver
17
+ @event_executor_group = event_executor_group
18
+ @domain_name_resolver = Internal::Validator.require_non_nil!(domain_name_resolver)
19
+ end
20
+
21
+ # Given a database and its current routing table, and the global connection pool, use the global cluster composition provider to fetch a new cluster
22
+ # composition, which would be used to update the routing table of the given database and global connection pool.
23
+
24
+ # @param routingTable current routing table of the given database.
25
+ # @param connectionPool connection pool.
26
+ # @return new cluster composition and an optional set of resolved initial router addresses.
27
+ def lookup_cluster_composition(routing_table, connection_pool, bookmark, impersonated_user, failures = nil, previous_delay = nil, result = nil, base_error = nil)
28
+ result = java.util.concurrent.CompletableFuture.new
29
+
30
+ # if we failed discovery, we will chain all errors into this one.
31
+ base_error = Exceptions::ServiceUnavailableException.new(NO_ROUTERS_AVAILABLE % routing_table.database.description)
32
+
33
+ lookup(routing_table, connection_pool, bookmark, impersonated_user, base_error).when_complete do |composition_lookup_result, completion_error|
34
+ error = Util::Futures.completion_exception_cause(completion_error)
35
+
36
+ if !error.nil?
37
+ result.complete_exceptionally(error)
38
+ elsif !composition_lookup_result.nil?
39
+ result.complete(composition_lookup_result)
40
+ else
41
+ new_failures = failures + 1
42
+
43
+ if new_failures >= @settings.max_routing_failures
44
+ # now we throw our saved error out
45
+ result.complete_exceptionally(base_error)
46
+ else
47
+ next_delay = java.lang.Math.max(@settings.retry_timeout_delay, previous_delay * 2)
48
+ @log.info("Unable to fetch new routing table, will try again in #{next_delay} ms")
49
+
50
+ @event_executor_group.next.schedule(next_delay, java.util.concurrent.TimeUnit::MILLISECONDS) do
51
+ lookup_cluster_composition(routing_table, connection_pool, bookmark, impersonated_user, new_failures, next_delay, result, base_error)
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ result
58
+ end
59
+
60
+ def resolve
61
+ resolved_addresses = java.util.LinkedList.new
62
+ exception = nil
63
+
64
+ @resolver.resolve(initial_router).each do |server_address|
65
+ begin
66
+ resolve_all_by_domain_name(server_address).unicast_stream.for_each(resolved_addresses::add)
67
+ rescue java.net.UnknownHostException => e
68
+ if exception.nil?
69
+ exception = e
70
+ else
71
+ exception.add_suppressed(e)
72
+ end
73
+ end
74
+ end
75
+
76
+ # give up only if there are no addresses to work with at all
77
+ if resolved_addresses.empty? && !exception.nil?
78
+ raise exception
79
+ end
80
+
81
+ resolved_addresses
82
+ end
83
+
84
+ private
85
+
86
+ def lookup(routing_table, connection_pool, bookmark, impersonated_user, base_error)
87
+ composition_stage = if routing_table.prefer_initial_router
88
+ lookup_on_initial_router_then_on_known_routers(routing_table, connection_pool, bookmark, impersonated_user, base_error)
89
+ else
90
+ lookup_on_known_routers_then_on_initial_router(routing_table, connection_pool, bookmark, impersonated_user, base_error)
91
+ end
92
+ end
93
+
94
+ def lookup_on_known_routers_then_on_initial_router(routing_table, connection_pool, bookmark, impersonated_user, base_error)
95
+ seen_servers = {}
96
+
97
+ lookup_on_known_routers(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error).then_compose do |composition_lookup_result|
98
+ if composition_lookup_result.nil?
99
+ java.util.concurrent.CompletableFuture.completed_future(composition_lookup_result)
100
+ end
101
+
102
+ lookup_on_initial_router(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
103
+ end
104
+ end
105
+
106
+ def lookup_on_initial_router_then_on_known_routers(routing_table, connection_pool, bookmark, impersonated_user, base_error)
107
+ seen_servers = [].freeze
108
+
109
+ lookup_on_initial_router(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error).then_compose do |composition_lookup_result|
110
+ if composition_lookup_result.nil?
111
+ java.util.concurrent.CompletableFuture.completed_future(composition_lookup_result)
112
+ end
113
+
114
+ lookup_on_known_routers(routing_table, connection_pool, {}, bookmark, impersonated_user, base_error)
115
+ end
116
+ end
117
+
118
+ def lookup_on_known_routers(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
119
+ result = Util::Futures.completed_with_null
120
+
121
+ routing_table.routers.each do |address|
122
+ result = result.then_compose do |composition|
123
+ if !composition.nil?
124
+ java.util.concurrent.CompletableFuture.completed_future(composition)
125
+ else
126
+ lookup_on_router(address, true, routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
127
+ end
128
+ end
129
+ end
130
+
131
+ result.then_apply do |composition|
132
+ composition.nil? ? nil : ClusterCompositionLookupResult.new(composition)
133
+ end
134
+ end
135
+
136
+ def lookup_on_initial_router(routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
137
+ begin
138
+ resolved_routers = resolve
139
+ rescue StandardError => error
140
+ Util::Futures.failed_future(error)
141
+ end
142
+
143
+ resolved_router_set = [resolved_routers]
144
+ resolved_routers - seen_servers
145
+
146
+ result = Util::Futures.completed_with_null
147
+
148
+ resolved_routers.each do |address|
149
+ result = result.then_compose do |composition|
150
+ if !composition.nil?
151
+ java.util.concurrent.CompletableFuture.completed_future(composition)
152
+ else
153
+ lookup_on_router(address, false, routing_table, connection_pool, nil, bookmark, impersonated_user, base_error)
154
+ end
155
+ end
156
+ end
157
+
158
+ result.then_apply do |composition|
159
+ composition.nil? ? nil : ClusterCompositionLookupResult.new(composition, resolved_router_set)
160
+ end
161
+ end
162
+
163
+ def lookup_on_router(router_address, resolve_address, routing_table, connection_pool, seen_servers, bookmark, impersonated_user, base_error)
164
+ address_future = java.util.concurrent.CompletableFuture.completed_future(router_address)
165
+
166
+ address_future.then_apply do |address|
167
+ resolve_address ? resolve_by_domain_name_or_throw_completion_exception(address, routing_table) : address
168
+ end.then_apply do |address|
169
+ add_and_return(seen_servers, address)
170
+ end.then_compose do
171
+ connection_pool::acquire
172
+ end.then_apply do |connection|
173
+ ImpersonationUtil.ensure_impersonation_support(connection, impersonated_user)
174
+ end.then_compose do |connection|
175
+ @provider.get_cluster_composition(connection, routing_table.database, bookmark, impersonated_user)
176
+ end.handle do |response, error|
177
+ cause = Util::Futures.completion_exception_cause(error)
178
+
179
+ if !cause.nil?
180
+ handle_routing_procedure_error(cause, routing_table, router_address, base_error)
181
+ else
182
+ response
183
+ end
184
+ end
185
+ end
186
+
187
+ def handle_routing_procedure_error(error, routing_table, router_address, base_error)
188
+ raise java.util.concurrent.CompletionException, error if must_abort_discovery(error)
189
+
190
+ # Retriable error happened during discovery.
191
+ discovery_error = Exceptions::DiscoveryException.new(RECOVERABLE_ROUTING_ERROR % router_address, error)
192
+ Util::Futures.combine_errors(base_error, discovery_error) # we record each failure here
193
+ warning_message = RECOVERABLE_DISCOVERY_ERROR_WITH_SERVER % router_address
194
+ @log.warn(warning_message)
195
+ @log.debug(warning_message, discovery_error)
196
+ routing_table.forget(router_address)
197
+ nil
198
+ end
199
+
200
+ def must_abort_discovery(throwable)
201
+ abort = if !(throwable.is_a? Exceptions::AuthorizationExpiredException) && (throwable.is_a? Exceptions::SecurityException)
202
+ true
203
+ elsif throwable.is_a? Exceptions::FatalDiscoveryException
204
+ true
205
+ elsif throwable.is_a? Exceptions::IllegalStateException && Spi::ConnectionPool::CONNECTION_POOL_CLOSED_ERROR_MESSAGE == throwable.message
206
+ true
207
+ elsif throwable.is_a? Exceptions::ClientException
208
+ code = throwable.code
209
+ INVALID_BOOKMARK_CODE.eql?(code) || INVALID_BOOKMARK_MIXTURE_CODE.eql?(code)
210
+ end
211
+ end
212
+
213
+ def add_and_return(collection, element)
214
+ collection << element unless collection.nil?
215
+
216
+ element
217
+ end
218
+
219
+ def resolve_by_domain_name_or_throw_completion_exception(address, routing_table)
220
+ begin
221
+ resolved_address = resolve_all_by_domain_name(address)
222
+ routing_table.replace_router_if_present(address, resolved_address)
223
+
224
+ resolved_address.unicast_stream.find_first.or_else_throw do
225
+ Exceptions::IllegalStateException.new('Unexpected condition, the ResolvedBoltServerAddress must always have at least one unicast address')
226
+ end
227
+ rescue StandardError => e
228
+ raise java.util.concurrent.CompletionException, e
229
+ end
230
+ end
231
+
232
+ def resolve_all_by_domain_name(address)
233
+ ResolvedBoltServerAddress.new(address.host, address.port, domain_name_resolver.resolve(address.host))
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,43 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Cluster
4
+ # This implementation of the {@link RoutingProcedureRunner} access the routing procedure
5
+ # through the bolt's ROUTE message.
6
+ class RouteMessageRoutingProcedureRunner
7
+ attr_writer :routing_table
8
+
9
+ def initialize(routing_context)
10
+ @routing_context = routing_context.to_h
11
+ end
12
+
13
+ def run(connection, database_name, bookmark, impersonated_user)
14
+ direct_connection = to_direct_connection(connection, database_name, impersonated_user)
15
+ direct_connection.write_and_flush(
16
+ Messaging::Request::RouteMessage.new(@routing_context, bookmark, database_name.database_name,
17
+ impersonated_user),
18
+ Handlers::RouteMessageResponseHandler.new(self))
19
+ RoutingProcedureResponse.new(query(database_name), to_record(routing_table))
20
+ rescue => e
21
+ RoutingProcedureResponse.new(query(database_name), e)
22
+ ensure
23
+ direct_connection.release
24
+ end
25
+
26
+ private
27
+
28
+ def to_record(routing_table)
29
+ InternalRecord.new(routing_table.keys, routing_table.values)
30
+ end
31
+
32
+ def to_direct_connection(connection, database_name, impersonated_user)
33
+ Async::Connection::DirectConnection.new(connection, database_name, AccessMode::READ, impersonated_user)
34
+ end
35
+
36
+ def query(database_name)
37
+ Query.new('ROUTE $routing_context $database_name', routing_context: @routing_context,
38
+ database_name: database_name.database_name)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,77 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Cluster
4
+ class RoutingContext
5
+ include Scheme
6
+ EMPTY = new
7
+ ROUTING_ADDRESS_KEY = :address
8
+
9
+ def initialize(uri = nil)
10
+ if uri
11
+ @server_routing_enabled = routing_scheme?(uri.scheme)
12
+ @context = parse_parameters(uri).freeze
13
+ else
14
+ @server_routing_enabled = true
15
+ @context = {}
16
+ end
17
+ end
18
+
19
+ def defined?
20
+ @context.size > 1
21
+ end
22
+
23
+ def to_h
24
+ @context
25
+ end
26
+
27
+ def server_routing_enabled?
28
+ @server_routing_enabled
29
+ end
30
+
31
+ def to_s
32
+ "RoutingContext #{@context} ServerRoutingEnabled=#{@server_routing_enabled}"
33
+ end
34
+
35
+ private
36
+
37
+ def parse_parameters(uri)
38
+ query = uri.query
39
+ address = "#{uri.host}:#{uri.port || BoltServerAddress::DEFAULT_PORT}"
40
+ parameters = { ROUTING_ADDRESS_KEY => address }
41
+ return parameters if query.blank?
42
+
43
+ pairs = query.split('&')
44
+ pairs.each do |pair|
45
+ key_value = pair.split('=')
46
+
47
+ if key_value.size != 2
48
+ raise ArgumentError, "Invalid parameters: '#{pair}' in URI '#{uri}'"
49
+ end
50
+
51
+ key = trim_and_verify_key(key_value[0], 'key', uri)
52
+ if parameters.key?(key)
53
+ raise ArgumentError, "Duplicated query parameters with key '#{key}' in URI '#{uri}'"
54
+ end
55
+ parameters[key] = trim_and_verify(key_value[1], 'value', uri)
56
+ end
57
+
58
+ parameters
59
+ end
60
+
61
+ def trim_and_verify_key(s, key, uri)
62
+ trim_and_verify(s, key, uri).tap do |trimmed|
63
+ if trimmed == ROUTING_ADDRESS_KEY
64
+ raise ArgumentError, "The key 'address' is reserved for routing context."
65
+ end
66
+ end
67
+ end
68
+
69
+ def trim_and_verify(string, name, uri)
70
+ string.strip.tap do |result|
71
+ raise ArgumentError, "Illegal empty #{name} in URI query '#{uri}'" if result.empty?
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end