neo4j-ruby-driver 1.7.4 → 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.
Files changed (342) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +37 -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/driver/types/time.rb +4 -2
  33. data/lib/neo4j_ruby_driver.rb +5 -10
  34. data/{ffi → ruby}/neo4j/driver/access_mode.rb +2 -2
  35. data/ruby/neo4j/driver/auth_tokens.rb +34 -0
  36. data/ruby/neo4j/driver/bookmark.rb +21 -0
  37. data/ruby/neo4j/driver/config.rb +89 -0
  38. data/ruby/neo4j/driver/graph_database.rb +80 -0
  39. data/ruby/neo4j/driver/internal/async/connection/bolt_protocol_util.rb +51 -0
  40. data/ruby/neo4j/driver/internal/async/connection/bootstrap_factory.rb +22 -0
  41. data/ruby/neo4j/driver/internal/async/connection/channel_attributes.rb +31 -0
  42. data/ruby/neo4j/driver/internal/async/connection/channel_connected_listener.rb +32 -0
  43. data/ruby/neo4j/driver/internal/async/connection/channel_connector_impl.rb +83 -0
  44. data/ruby/neo4j/driver/internal/async/connection/channel_pipeline_builder_impl.rb +22 -0
  45. data/ruby/neo4j/driver/internal/async/connection/direct_connection.rb +30 -0
  46. data/ruby/neo4j/driver/internal/async/connection/event_loop_group_factory.rb +83 -0
  47. data/ruby/neo4j/driver/internal/async/connection/handshake_completed_listener.rb +27 -0
  48. data/ruby/neo4j/driver/internal/async/connection/handshake_handler.rb +113 -0
  49. data/ruby/neo4j/driver/internal/async/connection/netty_channel_initializer.rb +57 -0
  50. data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver.rb +26 -0
  51. data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver_group.rb +19 -0
  52. data/ruby/neo4j/driver/internal/async/connection/routing_connection.rb +36 -0
  53. data/ruby/neo4j/driver/internal/async/connection/stream.rb +12 -0
  54. data/ruby/neo4j/driver/internal/async/connection/stream_reader.rb +16 -0
  55. data/ruby/neo4j/driver/internal/async/connection_context.rb +10 -0
  56. data/ruby/neo4j/driver/internal/async/immutable_connection_context.rb +24 -0
  57. data/ruby/neo4j/driver/internal/async/inbound/byte_buf_input.rb +30 -0
  58. data/ruby/neo4j/driver/internal/async/inbound/channel_error_handler.rb +77 -0
  59. data/ruby/neo4j/driver/internal/async/inbound/chunk_decoder.rb +41 -0
  60. data/ruby/neo4j/driver/internal/async/inbound/connect_timeout_handler.rb +32 -0
  61. data/ruby/neo4j/driver/internal/async/inbound/connection_read_timeout_handler.rb +17 -0
  62. data/ruby/neo4j/driver/internal/async/inbound/inbound_message_dispatcher.rb +171 -0
  63. data/ruby/neo4j/driver/internal/async/inbound/inbound_message_handler.rb +42 -0
  64. data/ruby/neo4j/driver/internal/async/inbound/message_decoder.rb +51 -0
  65. data/ruby/neo4j/driver/internal/async/internal_async_session.rb +98 -0
  66. data/ruby/neo4j/driver/internal/async/internal_async_transaction.rb +13 -0
  67. data/ruby/neo4j/driver/internal/async/leak_logging_network_session.rb +34 -0
  68. data/ruby/neo4j/driver/internal/async/network_connection.rb +194 -0
  69. data/ruby/neo4j/driver/internal/async/network_session.rb +150 -0
  70. data/ruby/neo4j/driver/internal/async/outbound/chunk_aware_byte_buf_output.rb +110 -0
  71. data/ruby/neo4j/driver/internal/async/outbound/outbound_message_handler.rb +39 -0
  72. data/ruby/neo4j/driver/internal/async/pool/channel.rb +62 -0
  73. data/ruby/neo4j/driver/internal/async/pool/channel_pool.rb +31 -0
  74. data/ruby/neo4j/driver/internal/async/pool/channel_tracker.rb +135 -0
  75. data/ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb +156 -0
  76. data/ruby/neo4j/driver/internal/async/pool/netty_channel_health_checker.rb +87 -0
  77. data/ruby/neo4j/driver/internal/async/pool/netty_channel_pool.rb +52 -0
  78. data/ruby/neo4j/driver/internal/async/pool/network_connection_factory.rb +21 -0
  79. data/ruby/neo4j/driver/internal/async/pool/pool_settings.rb +34 -0
  80. data/ruby/neo4j/driver/internal/async/pool/timed_stack.rb +15 -0
  81. data/ruby/neo4j/driver/internal/async/result_cursors_holder.rb +17 -0
  82. data/ruby/neo4j/driver/internal/async/unmanaged_transaction.rb +212 -0
  83. data/ruby/neo4j/driver/internal/bookmark_holder.rb +9 -0
  84. data/ruby/neo4j/driver/internal/cluster/cluster_composition.rb +48 -0
  85. data/ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb +14 -0
  86. data/ruby/neo4j/driver/internal/cluster/cluster_routing_table.rb +122 -0
  87. data/ruby/neo4j/driver/internal/cluster/identity_resolver.rb +10 -0
  88. data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb +68 -0
  89. data/ruby/neo4j/driver/internal/cluster/loadbalancing/load_balancer.rb +125 -0
  90. data/ruby/neo4j/driver/internal/cluster/loadbalancing/round_robin_array_index.rb +13 -0
  91. data/ruby/neo4j/driver/internal/cluster/multi_databases_routing_procedure_runner.rb +31 -0
  92. data/ruby/neo4j/driver/internal/cluster/rediscovery_impl.rb +147 -0
  93. data/ruby/neo4j/driver/internal/cluster/route_message_routing_procedure_runner.rb +43 -0
  94. data/ruby/neo4j/driver/internal/cluster/routing_context.rb +77 -0
  95. data/ruby/neo4j/driver/internal/cluster/routing_procedure_cluster_composition_provider.rb +60 -0
  96. data/ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb +35 -0
  97. data/ruby/neo4j/driver/internal/cluster/routing_settings.rb +24 -0
  98. data/ruby/neo4j/driver/internal/cluster/routing_table_handler_impl.rb +95 -0
  99. data/ruby/neo4j/driver/internal/cluster/routing_table_registry_impl.rb +121 -0
  100. data/ruby/neo4j/driver/internal/cluster/single_database_routing_procedure_runner.rb +73 -0
  101. data/ruby/neo4j/driver/internal/connection_settings.rb +16 -0
  102. data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +55 -0
  103. data/ruby/neo4j/driver/internal/cursor/async_result_cursor_only_factory.rb +24 -0
  104. data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +61 -0
  105. data/ruby/neo4j/driver/internal/cursor/result_cursor_factory_impl.rb +24 -0
  106. data/ruby/neo4j/driver/internal/cursor/rx_result_cursor_impl.rb +110 -0
  107. data/ruby/neo4j/driver/internal/database_name_util.rb +37 -0
  108. data/ruby/neo4j/driver/internal/default_bookmark_holder.rb +9 -0
  109. data/ruby/neo4j/driver/internal/default_domain_name_resolver.rb +11 -0
  110. data/ruby/neo4j/driver/internal/direct_connection_provider.rb +40 -0
  111. data/ruby/neo4j/driver/internal/driver_factory.rb +126 -0
  112. data/ruby/neo4j/driver/internal/handlers/begin_tx_response_handler.rb +20 -0
  113. data/ruby/neo4j/driver/internal/handlers/channel_releasing_reset_response_handler.rb +30 -0
  114. data/ruby/neo4j/driver/internal/handlers/commit_tx_response_handler.rb +25 -0
  115. data/ruby/neo4j/driver/internal/handlers/hello_response_handler.rb +65 -0
  116. data/ruby/neo4j/driver/internal/handlers/init_response_handler.rb +34 -0
  117. data/ruby/neo4j/driver/internal/handlers/legacy_pull_all_response_handler.rb +199 -0
  118. data/ruby/neo4j/driver/internal/handlers/no_op_response_handler.rb +16 -0
  119. data/ruby/neo4j/driver/internal/handlers/ping_response_handler.rb +29 -0
  120. data/ruby/neo4j/driver/internal/handlers/pull_handlers.rb +32 -0
  121. data/ruby/neo4j/driver/internal/handlers/pulln/auto_pull_response_handler.rb +168 -0
  122. data/ruby/neo4j/driver/internal/handlers/pulln/basic_pull_response_handler.rb +298 -0
  123. data/ruby/neo4j/driver/internal/handlers/pulln/fetch_size_util.rb +20 -0
  124. data/ruby/neo4j/driver/internal/handlers/reset_response_handler.rb +34 -0
  125. data/ruby/neo4j/driver/internal/handlers/rollback_tx_response_handler.rb +25 -0
  126. data/ruby/neo4j/driver/internal/handlers/route_message_response_handler.rb +21 -0
  127. data/ruby/neo4j/driver/internal/handlers/routing_response_handler.rb +70 -0
  128. data/ruby/neo4j/driver/internal/handlers/run_response_handler.rb +38 -0
  129. data/ruby/neo4j/driver/internal/handlers/session_pull_response_completion_listener.rb +34 -0
  130. data/ruby/neo4j/driver/internal/handlers/transaction_pull_response_completion_listener.rb +20 -0
  131. data/ruby/neo4j/driver/internal/impersonation_util.rb +22 -0
  132. data/ruby/neo4j/driver/internal/internal_bookmark.rb +36 -0
  133. data/ruby/neo4j/driver/internal/internal_database_name.rb +9 -0
  134. data/ruby/neo4j/driver/internal/internal_driver.rb +74 -0
  135. data/ruby/neo4j/driver/internal/internal_entity.rb +20 -0
  136. data/ruby/neo4j/driver/internal/internal_node.rb +21 -0
  137. data/ruby/neo4j/driver/internal/internal_pair.rb +9 -0
  138. data/ruby/neo4j/driver/internal/internal_path.rb +35 -0
  139. data/ruby/neo4j/driver/internal/internal_point2_d.rb +9 -0
  140. data/ruby/neo4j/driver/internal/internal_point3_d.rb +6 -0
  141. data/{ffi → ruby}/neo4j/driver/internal/internal_record.rb +2 -1
  142. data/ruby/neo4j/driver/internal/internal_relationship.rb +26 -0
  143. data/ruby/neo4j/driver/internal/internal_result.rb +49 -0
  144. data/ruby/neo4j/driver/internal/internal_session.rb +81 -0
  145. data/ruby/neo4j/driver/internal/internal_transaction.rb +48 -0
  146. data/ruby/neo4j/driver/internal/logging/channel_activity_logger.rb +29 -0
  147. data/ruby/neo4j/driver/internal/logging/channel_error_logger.rb +17 -0
  148. data/ruby/neo4j/driver/internal/logging/prefixed_logger.rb +19 -0
  149. data/ruby/neo4j/driver/internal/logging/reformatted_logger.rb +17 -0
  150. data/ruby/neo4j/driver/internal/messaging/abstract_message_writer.rb +23 -0
  151. data/ruby/neo4j/driver/internal/messaging/bolt_protocol.rb +30 -0
  152. data/ruby/neo4j/driver/internal/messaging/bolt_protocol_version.rb +48 -0
  153. data/ruby/neo4j/driver/internal/messaging/common/common_message_reader.rb +51 -0
  154. data/ruby/neo4j/driver/internal/messaging/common/common_value.rb +31 -0
  155. data/ruby/neo4j/driver/internal/messaging/common/common_value_packer.rb +101 -0
  156. data/ruby/neo4j/driver/internal/messaging/common/common_value_unpacker.rb +234 -0
  157. data/ruby/neo4j/driver/internal/messaging/encode/begin_message_encoder.rb +15 -0
  158. data/ruby/neo4j/driver/internal/messaging/encode/commit_message_encoder.rb +14 -0
  159. data/ruby/neo4j/driver/internal/messaging/encode/discard_all_message_encoder.rb +14 -0
  160. data/ruby/neo4j/driver/internal/messaging/encode/discard_message_encoder.rb +15 -0
  161. data/ruby/neo4j/driver/internal/messaging/encode/goodbye_message_encoder.rb +14 -0
  162. data/ruby/neo4j/driver/internal/messaging/encode/hello_message_encoder.rb +15 -0
  163. data/ruby/neo4j/driver/internal/messaging/encode/init_message_encoder.rb +16 -0
  164. data/ruby/neo4j/driver/internal/messaging/encode/pull_all_message_encoder.rb +14 -0
  165. data/ruby/neo4j/driver/internal/messaging/encode/pull_message_encoder.rb +15 -0
  166. data/ruby/neo4j/driver/internal/messaging/encode/reset_message_encoder.rb +14 -0
  167. data/ruby/neo4j/driver/internal/messaging/encode/rollback_message_encoder.rb +14 -0
  168. data/ruby/neo4j/driver/internal/messaging/encode/route_message_encoder.rb +24 -0
  169. data/ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb +22 -0
  170. data/ruby/neo4j/driver/internal/messaging/encode/run_message_encoder.rb +16 -0
  171. data/ruby/neo4j/driver/internal/messaging/encode/run_with_metadata_message_encoder.rb +17 -0
  172. data/ruby/neo4j/driver/internal/messaging/request/abstract_streaming_message.rb +25 -0
  173. data/ruby/neo4j/driver/internal/messaging/request/begin_message.rb +25 -0
  174. data/ruby/neo4j/driver/internal/messaging/request/commit_message.rb +20 -0
  175. data/ruby/neo4j/driver/internal/messaging/request/discard_all_message.rb +20 -0
  176. data/ruby/neo4j/driver/internal/messaging/request/discard_message.rb +23 -0
  177. data/ruby/neo4j/driver/internal/messaging/request/goodbye_message.rb +20 -0
  178. data/ruby/neo4j/driver/internal/messaging/request/hello_message.rb +31 -0
  179. data/ruby/neo4j/driver/internal/messaging/request/init_message.rb +19 -0
  180. data/ruby/neo4j/driver/internal/messaging/request/message_with_metadata.rb +10 -0
  181. data/ruby/neo4j/driver/internal/messaging/request/multi_database_util.rb +26 -0
  182. data/ruby/neo4j/driver/internal/messaging/request/pull_all_message.rb +23 -0
  183. data/ruby/neo4j/driver/internal/messaging/request/pull_message.rb +22 -0
  184. data/ruby/neo4j/driver/internal/messaging/request/reset_message.rb +32 -0
  185. data/ruby/neo4j/driver/internal/messaging/request/rollback_message.rb +20 -0
  186. data/ruby/neo4j/driver/internal/messaging/request/route_message.rb +28 -0
  187. data/ruby/neo4j/driver/internal/messaging/request/run_message.rb +23 -0
  188. data/ruby/neo4j/driver/internal/messaging/request/run_with_metadata_message.rb +49 -0
  189. data/ruby/neo4j/driver/internal/messaging/request/transaction_metadata_builder.rb +24 -0
  190. data/ruby/neo4j/driver/internal/messaging/response/failure_message.rb +40 -0
  191. data/ruby/neo4j/driver/internal/messaging/response/ignored_message.rb +29 -0
  192. data/ruby/neo4j/driver/internal/messaging/response/record_message.rb +33 -0
  193. data/ruby/neo4j/driver/internal/messaging/response/success_message.rb +34 -0
  194. data/ruby/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +82 -0
  195. data/ruby/neo4j/driver/internal/messaging/v3/message_format_v3.rb +17 -0
  196. data/ruby/neo4j/driver/internal/messaging/v3/message_writer_v3.rb +27 -0
  197. data/ruby/neo4j/driver/internal/messaging/v4/bolt_protocol_v4.rb +29 -0
  198. data/ruby/neo4j/driver/internal/messaging/v4/message_format_v4.rb +17 -0
  199. data/ruby/neo4j/driver/internal/messaging/v4/message_writer_v4.rb +17 -0
  200. data/ruby/neo4j/driver/internal/messaging/v41/bolt_protocol_v41.rb +25 -0
  201. data/ruby/neo4j/driver/internal/messaging/v42/bolt_protocol_v42.rb +13 -0
  202. data/ruby/neo4j/driver/internal/messaging/v43/bolt_protocol_v43.rb +19 -0
  203. data/ruby/neo4j/driver/internal/messaging/v43/message_format_v43.rb +18 -0
  204. data/ruby/neo4j/driver/internal/messaging/v43/message_writer_v43.rb +20 -0
  205. data/ruby/neo4j/driver/internal/messaging/v44/bolt_protocol_v44.rb +17 -0
  206. data/ruby/neo4j/driver/internal/messaging/v44/message_format_v44.rb +18 -0
  207. data/ruby/neo4j/driver/internal/messaging/v44/message_writer_v44.rb +15 -0
  208. data/ruby/neo4j/driver/internal/metrics/connection_pool_metrics_listener.rb +34 -0
  209. data/ruby/neo4j/driver/internal/metrics/internal_abstract_metrics.rb +46 -0
  210. data/ruby/neo4j/driver/internal/metrics/internal_connection_pool_metrics.rb +105 -0
  211. data/ruby/neo4j/driver/internal/metrics/internal_metrics.rb +82 -0
  212. data/ruby/neo4j/driver/internal/metrics/internal_metrics_provider.rb +18 -0
  213. data/ruby/neo4j/driver/internal/metrics/listener_event.rb +17 -0
  214. data/ruby/neo4j/driver/internal/metrics/metrics_provider.rb +24 -0
  215. data/ruby/neo4j/driver/internal/metrics/time_recorder_listener_event.rb +15 -0
  216. data/ruby/neo4j/driver/internal/packstream/byte_array_incompatible_packer.rb +12 -0
  217. data/ruby/neo4j/driver/internal/packstream/pack_input.rb +47 -0
  218. data/ruby/neo4j/driver/internal/packstream/pack_output.rb +39 -0
  219. data/ruby/neo4j/driver/internal/packstream/pack_stream.rb +326 -0
  220. data/ruby/neo4j/driver/internal/packstream/pack_type.rb +17 -0
  221. data/ruby/neo4j/driver/internal/read_only_bookmark_holder.rb +13 -0
  222. data/ruby/neo4j/driver/internal/resolved_bolt_server_address.rb +35 -0
  223. data/ruby/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb +151 -0
  224. data/ruby/neo4j/driver/internal/revocation_strategy.rb +19 -0
  225. data/ruby/neo4j/driver/internal/scheme.rb +32 -0
  226. data/ruby/neo4j/driver/internal/security/internal_auth_token.rb +15 -0
  227. data/ruby/neo4j/driver/internal/security/security_plan_impl.rb +48 -0
  228. data/ruby/neo4j/driver/internal/security_setting.rb +66 -0
  229. data/ruby/neo4j/driver/internal/session_factory_impl.rb +32 -0
  230. data/ruby/neo4j/driver/internal/spi/connection.rb +19 -0
  231. data/ruby/neo4j/driver/internal/spi/connection_pool.rb +9 -0
  232. data/ruby/neo4j/driver/internal/spi/response_handler.rb +23 -0
  233. data/ruby/neo4j/driver/internal/summary/internal_database_info.rb +7 -0
  234. data/ruby/neo4j/driver/internal/summary/internal_input_position.rb +11 -0
  235. data/ruby/neo4j/driver/internal/summary/internal_notification.rb +16 -0
  236. data/ruby/neo4j/driver/internal/summary/internal_plan.rb +41 -0
  237. data/ruby/neo4j/driver/internal/summary/internal_profiled_plan.rb +32 -0
  238. data/ruby/neo4j/driver/internal/summary/internal_result_summary.rb +33 -0
  239. data/ruby/neo4j/driver/internal/summary/internal_server_info.rb +6 -0
  240. data/ruby/neo4j/driver/internal/summary/internal_summary_counters.rb +18 -0
  241. data/ruby/neo4j/driver/internal/svm/netty_substitutions.rb +196 -0
  242. data/ruby/neo4j/driver/internal/svm/z_lib_substitutions.rb +21 -0
  243. data/ruby/neo4j/driver/internal/util/certificate_tool.rb +65 -0
  244. data/ruby/neo4j/driver/internal/util/clock.rb +29 -0
  245. data/ruby/neo4j/driver/internal/util/error_util.rb +104 -0
  246. data/ruby/neo4j/driver/internal/util/extract.rb +123 -0
  247. data/ruby/neo4j/driver/internal/util/format.rb +39 -0
  248. data/ruby/neo4j/driver/internal/util/futures.rb +99 -0
  249. data/ruby/neo4j/driver/internal/util/iterables.rb +35 -0
  250. data/ruby/neo4j/driver/internal/util/lock_util.rb +23 -0
  251. data/ruby/neo4j/driver/internal/util/metadata_extractor.rb +107 -0
  252. data/ruby/neo4j/driver/internal/util/mutex.rb +9 -0
  253. data/ruby/neo4j/driver/internal/util/preconditions.rb +16 -0
  254. data/ruby/neo4j/driver/internal/util/result_holder.rb +72 -0
  255. data/ruby/neo4j/driver/internal/util/server_version.rb +60 -0
  256. data/ruby/neo4j/driver/logging1.rb +51 -0
  257. data/ruby/neo4j/driver/net/server_address.rb +9 -0
  258. data/ruby/neo4j/driver/query.rb +48 -0
  259. data/ruby/neo4j/driver/records.rb +13 -0
  260. data/ruby/neo4j/driver/transaction_config.rb +50 -0
  261. data/ruby/neo4j/driver/values.rb +26 -0
  262. data/{lib → ruby}/neo4j/driver/version.rb +1 -1
  263. data/ruby/neo4j/driver.rb +29 -0
  264. metadata +264 -101
  265. data/ffi/bolt/address.rb +0 -11
  266. data/ffi/bolt/address_resolver.rb +0 -12
  267. data/ffi/bolt/address_set.rb +0 -9
  268. data/ffi/bolt/auth.rb +0 -10
  269. data/ffi/bolt/auto_releasable.rb +0 -22
  270. data/ffi/bolt/boolean.rb +0 -9
  271. data/ffi/bolt/bytes.rb +0 -10
  272. data/ffi/bolt/config.rb +0 -45
  273. data/ffi/bolt/connection.rb +0 -44
  274. data/ffi/bolt/connector.rb +0 -17
  275. data/ffi/bolt/dictionary.rb +0 -15
  276. data/ffi/bolt/error.rb +0 -74
  277. data/ffi/bolt/float.rb +0 -9
  278. data/ffi/bolt/integer.rb +0 -9
  279. data/ffi/bolt/library.rb +0 -12
  280. data/ffi/bolt/lifecycle.rb +0 -9
  281. data/ffi/bolt/list.rb +0 -10
  282. data/ffi/bolt/log.rb +0 -16
  283. data/ffi/bolt/socket_options.rb +0 -14
  284. data/ffi/bolt/status.rb +0 -25
  285. data/ffi/bolt/string.rb +0 -9
  286. data/ffi/bolt/structure.rb +0 -10
  287. data/ffi/bolt/value.rb +0 -35
  288. data/ffi/neo4j/driver/auth_tokens.rb +0 -18
  289. data/ffi/neo4j/driver/config.rb +0 -40
  290. data/ffi/neo4j/driver/graph_database.rb +0 -52
  291. data/ffi/neo4j/driver/internal/async/access_mode_connection.rb +0 -19
  292. data/ffi/neo4j/driver/internal/async/direct_connection.rb +0 -106
  293. data/ffi/neo4j/driver/internal/bolt_server_address.rb +0 -18
  294. data/ffi/neo4j/driver/internal/bookmarks_holder.rb +0 -30
  295. data/ffi/neo4j/driver/internal/direct_connection_provider.rb +0 -28
  296. data/ffi/neo4j/driver/internal/driver_factory.rb +0 -125
  297. data/ffi/neo4j/driver/internal/error_handling.rb +0 -112
  298. data/ffi/neo4j/driver/internal/explicit_transaction.rb +0 -146
  299. data/ffi/neo4j/driver/internal/handlers/pull_all_response_handler.rb +0 -104
  300. data/ffi/neo4j/driver/internal/handlers/response_handler.rb +0 -49
  301. data/ffi/neo4j/driver/internal/handlers/run_response_handler.rb +0 -32
  302. data/ffi/neo4j/driver/internal/handlers/session_pull_all_response_handler.rb +0 -32
  303. data/ffi/neo4j/driver/internal/handlers/transaction_pull_all_response_handler.rb +0 -23
  304. data/ffi/neo4j/driver/internal/internal_driver.rb +0 -45
  305. data/ffi/neo4j/driver/internal/internal_logger.rb +0 -32
  306. data/ffi/neo4j/driver/internal/internal_resolver.rb +0 -31
  307. data/ffi/neo4j/driver/internal/internal_statement_result.rb +0 -52
  308. data/ffi/neo4j/driver/internal/messaging/bolt_protocol.rb +0 -24
  309. data/ffi/neo4j/driver/internal/messaging/v1/bolt_protocol_v1.rb +0 -59
  310. data/ffi/neo4j/driver/internal/messaging/v2/bolt_protocol_v2.rb +0 -16
  311. data/ffi/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +0 -63
  312. data/ffi/neo4j/driver/internal/network_session.rb +0 -129
  313. data/ffi/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb +0 -80
  314. data/ffi/neo4j/driver/internal/session_factory_impl.rb +0 -28
  315. data/ffi/neo4j/driver/internal/summary/internal_result_summary.rb +0 -67
  316. data/ffi/neo4j/driver/internal/summary/internal_server_info.rb +0 -19
  317. data/ffi/neo4j/driver/internal/summary/internal_summary_counters.rb +0 -23
  318. data/ffi/neo4j/driver/internal/util/metadata_extractor.rb +0 -15
  319. data/ffi/neo4j/driver/internal/value/base_time_value.rb +0 -22
  320. data/ffi/neo4j/driver/internal/value/date_value.rb +0 -25
  321. data/ffi/neo4j/driver/internal/value/duration_value.rb +0 -27
  322. data/ffi/neo4j/driver/internal/value/local_date_time_value.rb +0 -24
  323. data/ffi/neo4j/driver/internal/value/local_time_value.rb +0 -19
  324. data/ffi/neo4j/driver/internal/value/node_value.rb +0 -18
  325. data/ffi/neo4j/driver/internal/value/offset_time_value.rb +0 -25
  326. data/ffi/neo4j/driver/internal/value/path_value.rb +0 -41
  327. data/ffi/neo4j/driver/internal/value/point2_d_value.rb +0 -24
  328. data/ffi/neo4j/driver/internal/value/point3_d_value.rb +0 -24
  329. data/ffi/neo4j/driver/internal/value/relationship_value.rb +0 -18
  330. data/ffi/neo4j/driver/internal/value/structure_value.rb +0 -42
  331. data/ffi/neo4j/driver/internal/value/time_with_zone_id_value.rb +0 -25
  332. data/ffi/neo4j/driver/internal/value/time_with_zone_offset_value.rb +0 -28
  333. data/ffi/neo4j/driver/internal/value/unbound_relationship_value.rb +0 -18
  334. data/ffi/neo4j/driver/internal/value/value_adapter.rb +0 -101
  335. data/ffi/neo4j/driver/net/server_address.rb +0 -13
  336. data/ffi/neo4j/driver/statement.rb +0 -15
  337. data/ffi/neo4j/driver/types/entity.rb +0 -21
  338. data/ffi/neo4j/driver/types/node.rb +0 -16
  339. data/ffi/neo4j/driver/types/path.rb +0 -35
  340. data/ffi/neo4j/driver/types/relationship.rb +0 -19
  341. data/ffi/neo4j/driver.rb +0 -61
  342. data/lib/neo4j/driver/internal/ruby_signature.rb +0 -18
@@ -0,0 +1,150 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Async
4
+ class NetworkSession
5
+ attr_reader :retry_logic
6
+
7
+ def initialize(connection_provider, retry_logic, database_name, mode, bookmark_holder, impersonated_user, fetch_size, logger)
8
+ @connection_provider = connection_provider
9
+ @mode = mode
10
+ @retry_logic = retry_logic
11
+ @log = Logging::PrefixedLogger.new("[#{hash}]", logger)
12
+ @bookmark_holder = bookmark_holder
13
+ # @database_name = database_name.database_name
14
+ @connection_context = NetworkSessionConnectionContext.new(database_name, @bookmark_holder.bookmark, impersonated_user)
15
+ @fetch_size = fetch_size
16
+ @open = Concurrent::AtomicBoolean.new(true)
17
+ end
18
+
19
+ def run_async(query, **config)
20
+ new_result_cursor = build_result_cursor_factory(query, config).async_result
21
+ @result_cursor = new_result_cursor
22
+ new_result_cursor.map_successful_run_completion_async
23
+ end
24
+
25
+ def begin_transaction_async(mode = @mode, **config)
26
+ ensure_session_is_open
27
+ ensure_no_open_tx_before_starting_tx
28
+ acquire_connection(mode).then do |connection|
29
+ ImpersonationUtil.ensure_impersonation_support(connection, connection.impersonated_user)
30
+ tx = UnmanagedTransaction.new(connection, @bookmark_holder, @fetch_size)
31
+ tx.begin_async(@bookmark_holder.bookmark, config)
32
+ end&.tap { |new_transaction| @transaction = new_transaction }
33
+ end
34
+
35
+ def reset_async
36
+ existing_transaction_or_null
37
+ .then_accept { |tx| tx&.mark_terminated }
38
+ .then_flat { @connection_stage }
39
+ .then_flat do |connection|
40
+ # there exists an active connection, send a RESET message over it
41
+ connection&.reset || Util::Futures.completed_with_null
42
+ end
43
+ end
44
+
45
+ def last_bookmark
46
+ @bookmark_holder.bookmark
47
+ end
48
+
49
+ def release_connection_async
50
+ @connection&.release
51
+ end
52
+
53
+ def connection_async
54
+ @connection
55
+ end
56
+
57
+ def open?
58
+ @open.true?
59
+ end
60
+
61
+ def close_async
62
+ return unless @open.make_false
63
+ # there exists a cursor with potentially unconsumed error, try to extract and propagate it
64
+ error = @result_cursor&.discard_all_failure_async
65
+ close_transaction_and_release_connection
66
+ rescue => tx_close_error
67
+ error = Util::Futures.combine_errors(error, tx_close_error)
68
+ ensure
69
+ raise error if error
70
+ end
71
+
72
+ def current_connection_open?
73
+ @connection&.open? # some connection has actually been acquired and it's still open
74
+ end
75
+
76
+ private
77
+
78
+ def build_result_cursor_factory(query, config)
79
+ ensure_session_is_open
80
+ ensure_no_open_tx_before_running_query
81
+ connection = acquire_connection(@mode)
82
+ ImpersonationUtil.ensure_impersonation_support(connection, connection.impersonated_user)
83
+ connection.protocol.run_in_auto_commit_transaction(connection, query, @bookmark_holder, config,
84
+ @fetch_size)
85
+ end
86
+
87
+ def acquire_connection(mode)
88
+ # make sure previous result is fully consumed and connection is released back to the pool
89
+ @result_cursor&.pull_all_failure_async&.result!&.then(&method(:raise))
90
+ if @connection&.open?
91
+ # there somehow is an existing open connection, this should not happen, just a precondition
92
+ raise Neo4j::Driver::Exceptions::IllegalStateException.new('Existing open connection detected')
93
+ end
94
+
95
+ @connection = @connection_provider.acquire_connection(@connection_context.context_with_mode(mode))
96
+ end
97
+
98
+ def close_transaction_and_release_connection
99
+ existing_transaction_or_null&.close_async
100
+ ensure
101
+ release_connection_async
102
+ end
103
+
104
+ def ensure_no_open_tx_before_running_query
105
+ ensure_no_open_tx('Queries cannot be run directly on a session with an open transaction; either run from within the transaction or use a different session.')
106
+ end
107
+
108
+ def ensure_no_open_tx_before_starting_tx
109
+ ensure_no_open_tx('You cannot begin a transaction on a session with an open transaction; either run from within the transaction or use a different session.')
110
+ end
111
+
112
+ def ensure_no_open_tx(error_message)
113
+ existing_transaction_or_null&.then do
114
+ raise Neo4j::Driver::Exceptions::TransactionNestingException.new(error_message)
115
+ end
116
+ end
117
+
118
+ def existing_transaction_or_null
119
+ @transaction if @transaction&.open?
120
+ end
121
+
122
+ def ensure_session_is_open
123
+ unless @open.true?
124
+ raise Neo4j::Driver::Exceptions::ClientException.new('No more interaction with this session are allowed as the current session is already closed.')
125
+ end
126
+ end
127
+
128
+ # The {@link NetworkSessionConnectionContext#mode} can be mutable for a session connection context
129
+ class NetworkSessionConnectionContext
130
+ # This bookmark is only used for rediscovery.
131
+ # It has to be the initial bookmark given at the creation of the session.
132
+ # As only that bookmark could carry extra system bookmarks
133
+ attr_accessor :database_name
134
+ attr :mode, :rediscovery_bookmark, :impersonated_user
135
+
136
+ def initialize(database_name, bookmark, impersonated_user)
137
+ @database_name = database_name
138
+ @rediscovery_bookmark = bookmark
139
+ @impersonated_user = impersonated_user
140
+ end
141
+
142
+ def context_with_mode(mode)
143
+ @mode = mode
144
+ self
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,110 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Async
4
+ module Outbound
5
+ class ChunkAwareByteBufOutput
6
+ include Packstream::PackStream::Packer
7
+ include Messaging::Common::CommonValuePacker
8
+
9
+ class ChunkBuffer < ::Async::IO::Buffer
10
+ include Packstream::PackOutput
11
+ alias write <<
12
+ end
13
+
14
+ def initialize(output, max_chunk_size: Connection::BoltProtocolUtil::DEFAULT_MAX_OUTBOUND_CHUNK_SIZE_BYTES)
15
+ @output = output
16
+ @max_chunk_size = verify_max_chunk_size(max_chunk_size)
17
+ @chunk = ChunkBuffer.new
18
+ end
19
+
20
+ def start
21
+ assert_not_started
22
+ @chunk.clear
23
+ end
24
+
25
+ def write_byte(value)
26
+ ensure_can_fit_in_current_chunk(1)
27
+ @chunk.write_byte(value)
28
+ self
29
+ end
30
+
31
+ def write(data)
32
+ offset = 0
33
+ length = data.bytesize
34
+
35
+ while offset < length
36
+ # Ensure there is an open chunk, and that it has at least one byte of space left
37
+ ensure_can_fit_in_current_chunk(1)
38
+
39
+ # Write as much as we can into the current chunk
40
+ amount_to_write = [available_bytes_in_current_chunk, length - offset].min
41
+
42
+ @chunk.write(data.byteslice(offset, amount_to_write))
43
+ offset += amount_to_write
44
+ end
45
+
46
+ self
47
+ end
48
+
49
+ def write_short(value)
50
+ ensure_can_fit_in_current_chunk(2)
51
+ @chunk.write_short(value)
52
+ self
53
+ end
54
+
55
+ def write_int(value)
56
+ ensure_can_fit_in_current_chunk(4)
57
+ @chunk.write_int(value)
58
+ self
59
+ end
60
+
61
+ def write_long(value)
62
+ ensure_can_fit_in_current_chunk(8)
63
+ @chunk.write_long(value)
64
+ self
65
+ end
66
+
67
+ def write_double(value)
68
+ ensure_can_fit_in_current_chunk(8)
69
+ @chunk.write_double(value)
70
+ self
71
+ end
72
+
73
+ def write_message_boundary
74
+ @output.write_short(0)
75
+ end
76
+
77
+ def write_chunk
78
+ @output.write_short(@chunk.bytesize)
79
+ @output.write(@chunk)
80
+ @chunk.clear
81
+ end
82
+
83
+ alias stop write_chunk
84
+
85
+ private
86
+
87
+ def ensure_can_fit_in_current_chunk(number_of_bytes)
88
+ write_chunk if @chunk.bytesize + number_of_bytes > @max_chunk_size
89
+ end
90
+
91
+ def available_bytes_in_current_chunk
92
+ @max_chunk_size - @chunk.bytesize
93
+ end
94
+
95
+ def assert_not_started
96
+ raise Neo4j::Driver::Exceptions::IllegalStateException.new('Already started') unless @chunk.empty?
97
+ end
98
+
99
+ def verify_max_chunk_size(max_chunk_size)
100
+ if max_chunk_size <= 0
101
+ raise ArgumentError.new("Max chunk size should be > 0, given: #{max_chunk_size}")
102
+ end
103
+
104
+ max_chunk_size
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,39 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Async
4
+ module Outbound
5
+ class OutboundMessageHandler
6
+ NAME = self.class.name
7
+
8
+ def initialize(output, message_format, logger)
9
+ @output = output
10
+ @writer = message_format.new_writer(output)
11
+ @log = logger
12
+ end
13
+
14
+ def handler_added(ctx)
15
+ @log = Logging::ChannelActivityLogger.new(ctx.channel, @log, self.class)
16
+ end
17
+
18
+ def handler_removed(ctx)
19
+ @log = nil
20
+ end
21
+
22
+ def encode(msg)
23
+ @log.debug("C: #{msg}")
24
+
25
+ @output.start
26
+ begin
27
+ @writer.write(msg)
28
+ ensure
29
+ @output.stop
30
+ end
31
+
32
+ @output.write_message_boundary
33
+ # @log.debug( "C: #{}") if @log.debug_enabled?
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,62 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Async
4
+ module Pool
5
+ class Channel
6
+ attr :stream
7
+ attr_accessor :version, :protocol, :message_format, :message_dispatcher
8
+ attr :attributes # should be attr
9
+ attr_accessor :auto_read
10
+
11
+ def initialize(address, connector, logger)
12
+ @attributes = Connection::ChannelAttributes.new
13
+ @stream = Connection::Stream.new(connector.connect(address))
14
+ @stream.write(Connection::BoltProtocolUtil.handshake_buf)
15
+ @stream.flush
16
+ Connection::HandshakeHandler.new(logger).decode(self)
17
+ stream_reader = Connection::StreamReader.new(@stream)
18
+ stream_writer = Outbound::ChunkAwareByteBufOutput.new(@stream)
19
+ @message_dispatcher = Inbound::InboundMessageDispatcher.new(self, logger)
20
+ @attributes[:message_dispatcher] = @message_dispatcher
21
+ @outbound_handler = Outbound::OutboundMessageHandler.new(stream_writer, message_format, logger)
22
+ @common_message_reader = Messaging::Common::CommonMessageReader.new(stream_reader)
23
+ connector.initialize_channel(self, protocol)
24
+ end
25
+
26
+ def close
27
+ @stream.close
28
+ end
29
+
30
+ def write(message)
31
+ @outbound_handler.encode(message)
32
+ end
33
+
34
+ def write_and_flush(message)
35
+ write(message)
36
+ @stream.flush
37
+ ensure_response_handling
38
+ end
39
+
40
+ private
41
+
42
+ def bracketless(host)
43
+ host.delete_prefix('[').delete_suffix(']')
44
+ end
45
+
46
+ def ensure_response_handling
47
+ # probably should be synchronized
48
+ return if @handling_active
49
+ @handling_active = true
50
+ while @message_dispatcher.queued_handlers_count > 0 do
51
+ @common_message_reader.read(@message_dispatcher)
52
+ end
53
+ @handling_active = false
54
+ rescue
55
+ @handling_active = false
56
+ raise
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -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
@@ -0,0 +1,135 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Async
4
+ module Pool
5
+ class ChannelTracker
6
+ attr_reader :lock, :read, :write, :address_to_in_use_channel_count, :address_to_idle_channel_count, :log,
7
+ :metrics_listener, :close_listener, :all_channels
8
+
9
+ def initialize(metrics_listener, logger, **options)
10
+ @metrics_listener = metrics_listener
11
+ @log = logger
12
+ @all_channels = options[:channels]
13
+ @lock = Concurrent::ReentrantReadWriteLock.new
14
+ @close_listener = method(:channel_closed)
15
+ end
16
+
17
+ def channel_released(channel)
18
+ @lock.with_write_lock do
19
+ decrement_in_use(channel)
20
+ increment_idle(channel)
21
+ channel.close_future.add_listener(close_listener)
22
+ end
23
+
24
+ log.debug("Channel [0x#{channel.id}] acquired from the pool. Local address: #{channel.local_address}, remote address: #{channel.remote_address}")
25
+ end
26
+
27
+ def channel_created(channel, creating_event = nil)
28
+ if creating_event.nil?
29
+ raise Neo4j::Driver::Exceptions::IllegalStateException.new('Untraceable channel created.')
30
+ else
31
+ # when it is created, we count it as idle as it has not been acquired out of the pool
32
+ do_in_write_lock(->() { increment_idle(channel) })
33
+
34
+ metrics_listener.after_created(Connection::ChannelAttributes.pool_id(channel), creating_event)
35
+ all_channels.add(channel)
36
+ log.debug( "Channel [0x#{channel.id}] created. Local address: #{channel.local_address}, remote address: #{channel.remote_address}")
37
+ end
38
+ end
39
+
40
+ def channel_creating(pool_id)
41
+ creating_event = metrics_listener.create_listener_event
42
+ metrics_listener.before_creating(pool_id, creating_event)
43
+ creating_event
44
+ end
45
+
46
+ def channel_failed_to_create(pool_id)
47
+ metrics_listener.after_failed_to_create(pool_id)
48
+ end
49
+
50
+ def channel_closed(channel)
51
+ do_in_write_lock(-> () { decrement_idle(channel) })
52
+ metrics_listener.after_closed(Connection::ChannelAttributes.pool_id(channel))
53
+ end
54
+
55
+ def in_use_channel_count(address)
56
+ retrieve_in_read_lock(-> () { address_to_in_use_channel_count.get_or_default(address, 0) })
57
+ end
58
+
59
+ def idle_channel_count(address)
60
+ retrieve_in_read_lock(-> () { address_to_idle_channel_count.get_or_default(address, 0) })
61
+ end
62
+
63
+ def prepare_to_close_channels
64
+ all_channels.each do |channel|
65
+ protocol = Messaging::BoltProtocol.for_channel(channel)
66
+ begin
67
+ protocol.prepare_to_close_channel(channel)
68
+ rescue Exception => e
69
+ # only logging it
70
+ log.debug( "Failed to prepare to close Channel #{channel} due to error #{e.get_message}. It is safe to ignore this error as the channel will be closed despite if it is successfully prepared to close or not.")
71
+ end
72
+ end
73
+ end
74
+
75
+
76
+ private
77
+
78
+ def increment_in_use(channel)
79
+ increment(channel, address_to_in_use_channel_count)
80
+ end
81
+
82
+ def decrement_in_use(channel)
83
+ address = Connection::ChannelAttributes.server_address(channel)
84
+
85
+ unless address_to_in_use_channel_count.contains_key(address)
86
+ raise Neo4j::Driver::Exceptions::IllegalStateException.new("No count exists for address '#{address}' in the 'in use' count")
87
+ end
88
+
89
+ count = address_to_in_use_channel_count.get(address)
90
+ address_to_in_use_channel_count.put(address, count - 1)
91
+ end
92
+
93
+ def increment_idle(channel)
94
+ increment(channel, address_to_idle_channel_count)
95
+ end
96
+
97
+ def decrement_idle(channel)
98
+ address = Connection::ChannelAttributes.server_address(channel)
99
+
100
+ unless address_to_idle_channel_count.contains_key(address)
101
+ raise Neo4j::Driver::Exceptions::IllegalStateException.new("No count exists for address '#{address}' in the 'idle' count")
102
+ end
103
+
104
+ count = address_to_idle_channel_count.get(address)
105
+ address_to_idle_channel_count.put(address, count - 1)
106
+ end
107
+
108
+ def increment(channel, count_map)
109
+ address = Connection::ChannelAttributes.server_address(channel)
110
+ count = count_map.compute_if_absent(address, -> (k) { 0 })
111
+ count_map.put(address, count + 1)
112
+ end
113
+
114
+ def do_in_write_lock(work)
115
+ begin
116
+ write.lock
117
+ work.run
118
+ ensure
119
+ write.unlock
120
+ end
121
+ end
122
+
123
+ def retrieve_in_read_lock(work)
124
+ begin
125
+ read.lock
126
+ work.get
127
+ ensure
128
+ read.unlock
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,156 @@
1
+ module Neo4j::Driver
2
+ module Internal
3
+ module Async
4
+ module Pool
5
+ class ConnectionPoolImpl
6
+ def initialize(connector, settings, logger)
7
+ @connector = connector
8
+ @settings = settings
9
+ @log = logger
10
+ @address_to_pool_lock = Concurrent::ReentrantReadWriteLock.new
11
+ @address_to_pool = {}
12
+ @closed = Concurrent::AtomicBoolean.new
13
+ end
14
+
15
+ def acquire(address)
16
+ @log.debug("Acquiring a connection from pool towards #{address}")
17
+
18
+ assert_not_closed
19
+ pool = get_or_create_pool(address)
20
+
21
+ begin
22
+ channel = pool.acquire
23
+ @log.debug { "Channel #{channel.object_id} acquired" }
24
+ rescue => error
25
+ process_acquisition_error(pool, address, error)
26
+ end
27
+ assert_not_closed(address, channel, pool)
28
+ NetworkConnection.new(channel, pool, @log) { remove(pool) }
29
+ end
30
+
31
+ def retain_all(addresses_to_retain)
32
+ @address_to_pool_lock.with_write_lock do
33
+ @address_to_pool.each do |address, pool|
34
+ unless addresses_to_retain.include?(address)
35
+ unless pool.busy?
36
+ # address is not present in updated routing table and has no active connections
37
+ # it's now safe to terminate corresponding connection pool and forget about it
38
+ @address_to_pool.delete(address)
39
+ if pool
40
+ @log.info("Closing connection pool towards #{address}, it has no active connections and is not in the routing table registry.")
41
+ close_pool_in_background(address, pool)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
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
+
55
+ def in_use_connections(address)
56
+ @address_to_pool[address]&.size || 0
57
+ # @netty_channel_tracker.in_use_channel_count(address)
58
+ end
59
+
60
+ def idle_connections(address)
61
+ @netty_channel_tracker.idle_channel_count(address)
62
+ end
63
+
64
+ def close
65
+ if @closed.make_true
66
+ @address_to_pool_lock.with_write_lock do
67
+ # We can only shutdown event loop group when all netty pools are fully closed,
68
+ # otherwise the netty pools might missing threads (from event loop group) to execute clean ups.
69
+ close_all_pools
70
+ @address_to_pool.clear
71
+ end
72
+ end
73
+ end
74
+
75
+ def open?(address)
76
+ @address_to_pool_lock.with_read_lock { @address_to_pool.key?(address) }
77
+ end
78
+
79
+ def to_string
80
+ @address_to_pool_lock.with_read_lock { "ConnectionPoolImpl{ pools=#{@address_to_pool}}" }
81
+ end
82
+
83
+ private
84
+
85
+ def process_acquisition_error(pool, server_address, error)
86
+ if error.is_a?(ConnectionPool::TimeoutError)
87
+ # NettyChannelPool returns future failed with TimeoutException if acquire operation takes more than
88
+ # configured time, translate this exception to a prettier one and re-throw
89
+ raise Neo4j::Driver::Exceptions::ClientException.new("Unable to acquire connection from the pool within configured maximum time of #{@settings.connection_acquisition_timeout.inspect}")
90
+ # elsif pool.closed?
91
+ # There is a race condition where a thread tries to acquire a connection while the pool is closed by another concurrent thread.
92
+ # Treat as failed to obtain connection for a direct driver. For a routing driver, this error should be retried.
93
+ # raise Neo4j::Driver::Exceptions::ServiceUnavailableException, "Connection pool for server #{server_address} is closed while acquiring a connection."
94
+ else
95
+ # some unknown error happened during connection acquisition, propagate it
96
+ raise error
97
+ end
98
+ end
99
+
100
+ def assert_not_closed(address = nil, channel = nil, pool = nil)
101
+ if @closed.true?
102
+ if address
103
+ pool.release(channel)
104
+ close_pool_in_background(address, pool)
105
+ @address_to_pool_lock.with_write_lock { @address_to_pool.delete(address) }
106
+ assert_not_closed
107
+ end
108
+ raise Exceptions::IllegalStateException, Spi::ConnectionPool::CONNECTION_POOL_CLOSED_ERROR_MESSAGE
109
+ end
110
+ end
111
+
112
+ # for testing only
113
+ protected def pool(address)
114
+ @address_to_pool_lock.with_read_lock { @address_to_pool[address] }
115
+ end
116
+
117
+ def new_pool(address)
118
+ ChannelPool.new(limit: @settings.max_connection_pool_size, acquisition_timeout: @settings.connection_acquisition_timeout) { Channel.new(address, @connector, @log) }
119
+ end
120
+
121
+ def get_or_create_pool(address)
122
+ @address_to_pool_lock.with_read_lock { @address_to_pool[address] } ||
123
+ @address_to_pool_lock.with_write_lock do
124
+ new_pool(address)&.tap do |pool|
125
+ # before the connection pool is added I can add the metrics for the pool.
126
+ # @metrics_listener.put_pool_metrics(pool.object_id, address, self)
127
+ @address_to_pool[address] = pool
128
+ end
129
+ end
130
+ end
131
+
132
+ def close_pool(pool)
133
+ pool.close
134
+ end
135
+
136
+ def close_pool_in_background(address, pool)
137
+ Async do
138
+ # Close in the background
139
+ close_pool(pool)
140
+ rescue => error
141
+ @log.warn("An error occurred while closing connection pool towards #{address}.", error)
142
+ end
143
+ end
144
+
145
+ def close_all_pools
146
+ @address_to_pool.map do |address, pool|
147
+ @log.info("Closing connection pool towards #{address}")
148
+ # Wait for all pools to be closed.
149
+ close_pool(pool)
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end