google-cloud-spanner 2.29.0 → 2.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c47f3cfa10a6d612de5578cd6602dece290f316246a809a265b504fc74737307
4
- data.tar.gz: fe95585faa6210cb5110dbc54e3bb95e0a9126577c1893854880ebd8232946a1
3
+ metadata.gz: '0048ff04c4a29b66a58595d58a68c5be48f765d5aa8e0f6fd5c27b0ca7b1c088'
4
+ data.tar.gz: 195570ee1bc8eb9b7c33d525df148aaa1a230693ae237b82f30d7e573866c3df
5
5
  SHA512:
6
- metadata.gz: fa836a8f8a9e7da61b9ca53e655a8ab0870dcc50435756af6d2637931b9f16c1f12853a4eab16038176ca4b85395f6d83d7cbccec9a8c37ad5c562f9ee83ad2e
7
- data.tar.gz: 873894c371f0f7e9679a4df3f4b8fdc28e0047f135584b11616bc25f53982ef42b378cd323c3216d2283f6517071d218dc8a1c7a60fb1b842bac9422fa0b3bda
6
+ metadata.gz: 37b100e79176dfc4fa89f80832ae04f81b7f8d027704bed6e0dcf217708fcbf7be3a2632961f55eda21fd0a4de7804eb2bd6b47172fa9901039d71d9018db99d
7
+ data.tar.gz: 5b308e03caf25c9b91ebb4c6433cb29a9eb4e3fe2c3fedbb81f624dc88a02858564ef2e1202ec4aca01021825db99a2fcf756ef978d6d18d23012428b568fa6b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Release History
2
2
 
3
+ ### 2.30.0 (2025-11-17)
4
+
5
+ #### Features
6
+
7
+ * implement support for Multiplexed Sessions ([#195](https://github.com/googleapis/ruby-spanner/issues/195))
8
+
3
9
  ### 2.29.0 (2025-11-06)
4
10
 
5
11
  #### Features
@@ -71,7 +71,9 @@ module Google
71
71
  ##
72
72
  # @private Creates a new Backup::Job instance.
73
73
  def initialize
74
+ # @type [::Gapic::Operation, nil]
74
75
  @grpc = nil
76
+ # @type [::Google::Cloud::Spanner::Service, nil]
75
77
  @service = nil
76
78
  end
77
79
 
@@ -268,7 +270,7 @@ module Google
268
270
  end
269
271
 
270
272
  # Create a new Backup::Job from a `Gapic::Operation` object.
271
- # @param grpc [::Gapic::Operation`] The wrapped `Gapic::Operation` object.
273
+ # @param grpc [::Gapic::Operation`] Underlying `Gapic::Operation` object.
272
274
  # @param service [::Google::Cloud::Spanner::Service] A `Spanner::Service` reference.
273
275
  # @private
274
276
  # @return [::Google::Cloud::Spanner::Backup::Job]
@@ -16,6 +16,8 @@
16
16
  require "google/cloud/spanner/errors"
17
17
  require "google/cloud/spanner/project"
18
18
  require "google/cloud/spanner/session"
19
+ require "google/cloud/spanner/session_cache"
20
+ require "google/cloud/spanner/session_creation_options"
19
21
  require "google/cloud/spanner/batch_snapshot"
20
22
 
21
23
  module Google
@@ -83,6 +85,16 @@ module Google
83
85
  @session_labels = session_labels
84
86
  @query_options = query_options
85
87
  @directed_read_options = directed_read_options
88
+
89
+ session_creation_options = SessionCreationOptions.new(
90
+ database_path: Admin::Database::V1::DatabaseAdmin::Paths.database_path(
91
+ project: @project.service.project, instance: instance_id, database: database_id
92
+ ),
93
+ session_labels: @session_labels,
94
+ query_options: @query_options
95
+ )
96
+
97
+ @session_cache = SessionCache.new @project.service, session_creation_options
86
98
  end
87
99
 
88
100
  # The unique identifier for the project.
@@ -110,13 +122,15 @@ module Google
110
122
  end
111
123
 
112
124
  # The Spanner instance connected to.
113
- # @return [Instance]
125
+ # @deprecated Use {Google::Cloud::Spanner::Admin::Instance#instance_admin} instead.
126
+ # @return [::Google::Cloud::Spanner::Instance]
114
127
  def instance
115
128
  @project.instance instance_id
116
129
  end
117
130
 
118
131
  # The Spanner database connected to.
119
- # @return [Database]
132
+ # @deprecated Use {Google::Cloud::Spanner::Admin::Database#database_admin} instead.
133
+ # @return [::Google::Cloud::Spanner::Database]
120
134
  def database
121
135
  @project.database instance_id, database_id
122
136
  end
@@ -428,12 +442,7 @@ module Google
428
442
  # @return [::Google::Cloud::Spanner::Session]
429
443
  def session
430
444
  ensure_service!
431
- grpc = @project.service.create_session \
432
- V1::Spanner::Paths.database_path(
433
- project: project_id, instance: instance_id, database: database_id
434
- ),
435
- labels: @session_labels
436
- Session.from_grpc grpc, @project.service, query_options: @query_options
445
+ @session_cache.session
437
446
  end
438
447
 
439
448
  ##
@@ -68,8 +68,15 @@ module Google
68
68
  # @private Directed Read Options
69
69
  attr_reader :directed_read_options
70
70
 
71
- ##
72
- # @private Creates a BatchSnapshot object.
71
+ # Creates a new `Spanner::BatchSnapshot` instance.
72
+ # @param grpc [::Google::Cloud::Spanner::V1::Transaction]
73
+ # Underlying `V1::Transaction` object.
74
+ # @param session [::Google::Cloud::Spanner::Session] A `Spanner::Session` reference.
75
+ # @param directed_read_options [::Hash, nil] Optional. Client options used to set
76
+ # the `directed_read_options` for all ReadRequests and ExecuteSqlRequests.
77
+ # Converts to `V1::DirectedReadOptions`. Example option: `:exclude_replicas`.
78
+ # @private
79
+ # @return [::Google::Cloud::Spanner::BatchSnapshot]
73
80
  def initialize grpc, session, directed_read_options: nil
74
81
  @grpc = grpc
75
82
  @session = session
@@ -852,9 +859,16 @@ module Google
852
859
  from_grpc transaction_grpc, Session.from_grpc(session_grpc, service, query_options: query_options)
853
860
  end
854
861
 
855
- ##
856
- # @private Creates a new BatchSnapshot instance from a
862
+ # Creates a new BatchSnapshot instance from a
857
863
  # `Google::Cloud::Spanner::V1::Transaction`.
864
+ # @param grpc [::Google::Cloud::Spanner::V1::Transaction]
865
+ # Underlying `V1::Transaction` object.
866
+ # @param session [::Google::Cloud::Spanner::Session] A `Spanner::Session` reference.
867
+ # @param directed_read_options [::Hash, nil] Optional. Client options used to set
868
+ # the `directed_read_options` for all ReadRequests and ExecuteSqlRequests.
869
+ # Converts to `V1::DirectedReadOptions`. Example option: `:exclude_replicas`.
870
+ # @private
871
+ # @return [::Google::Cloud::Spanner::BatchSnapshot]
858
872
  def self.from_grpc grpc, session, directed_read_options: nil
859
873
  new grpc, session, directed_read_options: directed_read_options
860
874
  end
@@ -19,10 +19,15 @@ module Google
19
19
  ##
20
20
  # @private Helper class to process BatchDML response
21
21
  class BatchUpdateResults
22
- ## Object of type
23
- # Google::Cloud::Spanner::V1::ExecuteBatchDmlResponse
22
+ # The `V1::ExecuteBatchDmlResponse` object to process
23
+ # @private
24
+ # @return [::Google::Cloud::Spanner::V1::ExecuteBatchDmlResponse]
24
25
  attr_reader :grpc
25
26
 
27
+ # Initializes the `BatchUpdateResults` helper
28
+ # @private
29
+ # @param grpc [::Google::Cloud::Spanner::V1::ExecuteBatchDmlResponse]
30
+ # The response from `ExecuteBatchDml` rpc to process in this helper.
26
31
  def initialize grpc
27
32
  @grpc = grpc
28
33
  end
@@ -16,7 +16,8 @@
16
16
  require "google/cloud/spanner/errors"
17
17
  require "google/cloud/spanner/project"
18
18
  require "google/cloud/spanner/data"
19
- require "google/cloud/spanner/pool"
19
+ require "google/cloud/spanner/session_cache"
20
+ require "google/cloud/spanner/session_creation_options"
20
21
  require "google/cloud/spanner/session"
21
22
  require "google/cloud/spanner/transaction"
22
23
  require "google/cloud/spanner/snapshot"
@@ -61,8 +62,9 @@ module Google
61
62
  # @param database_id [::String] Database id, e.g. `"my-database"`.
62
63
  # @param session_labels [::Hash, nil] Optional. The labels to be applied to all sessions
63
64
  # created by the client. Example: `"team" => "billing-service"`.
64
- # @param pool_opts [::Hash] Optional. `Spanner::Pool` creation options.
65
- # Example parameter: `:keepalive`.
65
+ # @param pool_opts [::Hash] Optional. Defaults to `{}`. Deprecated.
66
+ # @deprecated This parameter is non-functional since the multiplexed SessionCache does not require
67
+ # pool options.
66
68
  # @param query_options [::Hash, nil] Optional. A hash of values to specify the custom
67
69
  # query options for executing SQL query. Example parameter `:optimizer_version`.
68
70
  # @param database_role [::String, nil] Optional. The Spanner session creator role.
@@ -79,9 +81,21 @@ module Google
79
81
  @database_id = database_id
80
82
  @database_role = database_role
81
83
  @session_labels = session_labels
82
- @directed_read_options = directed_read_options
83
- @pool = Pool.new self, **pool_opts
84
84
  @query_options = query_options
85
+ @directed_read_options = directed_read_options
86
+
87
+ _pool_opts = pool_opts # unused. Here only to avoid having to disable Rubocop's Lint/UnusedMethodArgument
88
+
89
+ session_creation_options = SessionCreationOptions.new(
90
+ database_path: Admin::Database::V1::DatabaseAdmin::Paths.database_path(
91
+ project: @project.service.project, instance: instance_id, database: database_id
92
+ ),
93
+ session_labels: @session_labels,
94
+ session_creator_role: @database_role,
95
+ query_options: @query_options
96
+ )
97
+
98
+ @pool = SessionCache.new @project.service, session_creation_options
85
99
  end
86
100
 
87
101
  # The unique identifier for the project.
@@ -1943,7 +1957,8 @@ module Google
1943
1957
  # rubocop:disable Metrics/AbcSize
1944
1958
  # rubocop:disable Metrics/MethodLength
1945
1959
  # rubocop:disable Metrics/BlockLength
1946
-
1960
+ # rubocop:disable Metrics/CyclomaticComplexity
1961
+ # rubocop:disable Metrics/PerceivedComplexity
1947
1962
 
1948
1963
  ##
1949
1964
  # Creates a transaction for reads and writes that execute atomically at
@@ -2128,9 +2143,10 @@ module Google
2128
2143
  yield tx
2129
2144
 
2130
2145
  unless tx.existing_transaction?
2131
- # This can happen if the yielded `tx` object was only used to add mutations.
2146
+ # This typically will happen if the yielded `tx` object was only used to add mutations.
2132
2147
  # Then it never called any RPCs and didn't create a server-side Transaction object.
2133
2148
  # In which case we should make an explicit BeginTransaction call here.
2149
+
2134
2150
  tx.safe_begin_transaction!(
2135
2151
  exclude_from_change_streams: exclude_txn_from_change_streams,
2136
2152
  request_options: request_options,
@@ -2139,15 +2155,28 @@ module Google
2139
2155
  end
2140
2156
 
2141
2157
  transaction_id = tx.transaction_id
2142
- commit_resp = @project.service.commit(
2143
- tx.session.path,
2144
- tx.mutations,
2145
- transaction_id: transaction_id,
2146
- exclude_txn_from_change_streams: exclude_txn_from_change_streams,
2147
- commit_options: commit_options,
2148
- request_options: request_options,
2149
- call_options: call_options
2150
- )
2158
+
2159
+ # This "inner retry" mechanism is for Commit Response protocol.
2160
+ # Unlike the retry on `Aborted` errors it will not re-create a transaction.
2161
+ # This is intentional, as these retries are not related to e.g.
2162
+ # transactions deadlocking, so it's OK to retry "as-is".
2163
+ should_retry = true
2164
+ while should_retry
2165
+ commit_resp = @project.service.commit(
2166
+ tx.session.path,
2167
+ tx.mutations,
2168
+ transaction_id: transaction_id,
2169
+ exclude_txn_from_change_streams: exclude_txn_from_change_streams,
2170
+ commit_options: commit_options,
2171
+ request_options: request_options,
2172
+ call_options: call_options,
2173
+ precommit_token: tx.precommit_token
2174
+ )
2175
+
2176
+ tx.precommit_token = commit_resp.precommit_token
2177
+ should_retry = !commit_resp.precommit_token.nil?
2178
+ end
2179
+
2151
2180
  resp = CommitResponse.from_grpc commit_resp
2152
2181
  commit_options ? resp : resp.timestamp
2153
2182
  rescue GRPC::Aborted,
@@ -2157,8 +2186,16 @@ module Google
2157
2186
  check_and_propagate_err! e, (current_time - start_time > deadline)
2158
2187
  # Sleep the amount from RetryDelay, or incremental backoff
2159
2188
  sleep(delay_from_aborted(e) || backoff *= 1.3)
2189
+
2160
2190
  # Create new transaction on the session and retry the block
2161
- tx = session.create_transaction exclude_txn_from_change_streams: exclude_txn_from_change_streams
2191
+ previous_transaction_id = tx.transaction_id if tx.existing_transaction?
2192
+ tx = session.create_empty_transaction(
2193
+ exclude_txn_from_change_streams: exclude_txn_from_change_streams,
2194
+ previous_transaction_id: previous_transaction_id
2195
+ )
2196
+ if request_options
2197
+ tx.transaction_tag = request_options[:transaction_tag]
2198
+ end
2162
2199
  retry
2163
2200
  rescue StandardError => e
2164
2201
  # Rollback transaction when handling unexpected error
@@ -2176,6 +2213,9 @@ module Google
2176
2213
  # rubocop:enable Metrics/AbcSize
2177
2214
  # rubocop:enable Metrics/MethodLength
2178
2215
  # rubocop:enable Metrics/BlockLength
2216
+ # rubocop:enable Metrics/CyclomaticComplexity
2217
+ # rubocop:enable Metrics/PerceivedComplexity
2218
+
2179
2219
 
2180
2220
  ##
2181
2221
  # Creates a snapshot read-only transaction for reads that execute
@@ -2262,7 +2302,7 @@ module Google
2262
2302
  staleness: staleness || exact_staleness,
2263
2303
  call_options: call_options
2264
2304
  Thread.current[IS_TRANSACTION_RUNNING_KEY] = true
2265
- snp = Snapshot.from_grpc snp_grpc, session, @directed_read_options
2305
+ snp = Snapshot.from_grpc snp_grpc, session, directed_read_options: @directed_read_options
2266
2306
  yield snp if block_given?
2267
2307
  ensure
2268
2308
  Thread.current[IS_TRANSACTION_RUNNING_KEY] = nil
@@ -2442,58 +2482,8 @@ module Google
2442
2482
  ##
2443
2483
  # Reset the client sessions.
2444
2484
  #
2445
- def reset
2446
- @pool.reset
2447
- end
2448
-
2449
- # Creates a new Session objece.
2450
- # @param multiplexed [::Boolean] Optional. Default to `false`.
2451
- # If `true`, specifies a multiplexed session.
2452
- # @private
2453
- # @return [::Google::Cloud::Spanner::Session]
2454
- def create_new_session multiplexed: false
2455
- ensure_service!
2456
- grpc = @project.service.create_session \
2457
- Admin::Database::V1::DatabaseAdmin::Paths.database_path(
2458
- project: project_id, instance: instance_id, database: database_id
2459
- ),
2460
- labels: @session_labels,
2461
- database_role: @database_role,
2462
- multiplexed: multiplexed
2463
-
2464
- Session.from_grpc grpc, @project.service, query_options: @query_options
2465
- end
2466
-
2467
- ##
2468
- # @private
2469
- # Creates a batch of new session objects of size `total`.
2470
- # Makes multiple RPCs if necessary. Returns empty array if total is 0.
2471
- def batch_create_new_sessions total
2472
- sessions = []
2473
- remaining = total
2474
- while remaining.positive?
2475
- sessions += batch_create_sessions remaining
2476
- remaining = total - sessions.count
2477
- end
2478
- sessions
2479
- end
2480
-
2481
- ##
2482
- # @private
2483
- # The response may have fewer sessions than requested in the RPC.
2484
- #
2485
- def batch_create_sessions session_count
2486
- ensure_service!
2487
- resp = @project.service.batch_create_sessions \
2488
- Admin::Database::V1::DatabaseAdmin::Paths.database_path(
2489
- project: project_id, instance: instance_id, database: database_id
2490
- ),
2491
- session_count,
2492
- labels: @session_labels,
2493
- database_role: @database_role
2494
- resp.session.map do |grpc|
2495
- Session.from_grpc grpc, @project.service, query_options: @query_options
2496
- end
2485
+ def reset!
2486
+ @pool.reset!
2497
2487
  end
2498
2488
 
2499
2489
  # @private
@@ -2516,23 +2506,51 @@ module Google
2516
2506
  raise "Must have active connection to service" unless @project.service
2517
2507
  end
2518
2508
 
2519
- ##
2520
- # Check for valid snapshot arguments
2509
+ # Checks that the options hash contains exactly one valid single-use key.
2510
+ #
2511
+ # @param opts [::Hash, nil] The options hash to validate.
2512
+ # @private
2513
+ # @raise [ArgumentError] If the hash does not contain exactly one valid
2514
+ # single-use key.
2515
+ # @return [void]
2521
2516
  def validate_single_use_args! opts
2522
- return true if opts.nil? || opts.empty?
2523
- valid_keys = %i[strong timestamp read_timestamp staleness
2524
- exact_staleness bounded_timestamp
2525
- min_read_timestamp bounded_staleness max_staleness]
2526
- if opts.keys.count == 1 && valid_keys.include?(opts.keys.first)
2527
- return true
2528
- end
2517
+ # An empty options hash is valid.
2518
+ return if opts.nil? || opts.empty?
2519
+
2520
+ keys = opts.keys
2521
+
2522
+ valid_keys = Set.new(%i[
2523
+ strong timestamp read_timestamp staleness exact_staleness
2524
+ bounded_timestamp min_read_timestamp bounded_staleness max_staleness
2525
+ ]).freeze
2526
+
2527
+ # Raise an error unless there is exactly one key and it's in the valid set.
2528
+ return if keys.length == 1 && valid_keys.include?(keys.first)
2529
2529
  raise ArgumentError,
2530
- "Must provide only one of the following single_use values: " \
2531
- "#{valid_keys}"
2530
+ "Options must contain exactly one of the following keys: " \
2531
+ "#{valid_keys.to_a.join ', '}"
2532
2532
  end
2533
2533
 
2534
- ##
2535
- # Create a single-use TransactionSelector
2534
+ # Creates a selector for a single-use, read-only transaction.
2535
+ #
2536
+ # @param opts [::Hash] Options for creating the transaction selector.
2537
+ # If those are `nil` or empty, a `nil` will be returned instead of a `V1::TransactionSelector`.
2538
+ # @option opts [::Boolean] :strong
2539
+ # Executes a strong read.
2540
+ # @option opts [::Time, ::DateTime] :read_timestamp
2541
+ # Executes a read at the provided time. Alias: `:timestamp`.
2542
+ # @option opts [::Numeric] :exact_staleness
2543
+ # Executes a read at a time that is exactly this stale (in seconds).
2544
+ # Alias: `:staleness`.
2545
+ # @option opts [::Time, ::DateTime] :min_read_timestamp
2546
+ # Executes a read at a time that is at least this timestamp.
2547
+ # Alias: `:bounded_timestamp`.
2548
+ # @option opts [::Numeric] :max_staleness
2549
+ # Executes a read at a time that is at most this stale (in seconds).
2550
+ # Alias: `:bounded_staleness`.
2551
+ # @private
2552
+ # @return [V1::TransactionSelector, nil] The transaction selector object, or
2553
+ # `nil` if the `opts` hash is nil or empty.
2536
2554
  def single_use_transaction opts
2537
2555
  return nil if opts.nil? || opts.empty?
2538
2556
 
@@ -45,6 +45,7 @@ module Google
45
45
  ##
46
46
  # @private
47
47
  def initialize
48
+ # @type [Array<Google::Cloud::Spanner::V1::Mutation>]
48
49
  @mutations = []
49
50
  end
50
51
 
@@ -279,7 +280,9 @@ module Google
279
280
  keys
280
281
  end
281
282
 
283
+ # Return the current mutations added to this `Spanner::Commit` object.
282
284
  # @private
285
+ # @return [Array<Google::Cloud::Spanner::V1::Mutation>]
283
286
  def mutations
284
287
  @mutations
285
288
  end
@@ -53,8 +53,11 @@ module Google
53
53
  # puts commit_resp.stats.mutation_count
54
54
  #
55
55
  class CommitResponse
56
- ##
57
- # @private Creates a new CommitResponse instance.
56
+ # Creates a new CommitResponse instance.
57
+ #
58
+ # @param grpc [::Google::Cloud::Spanner::V1::CommitResponse]
59
+ # Underlying `V1::CommitResponse` object.
60
+ # @private
58
61
  def initialize grpc
59
62
  @grpc = grpc
60
63
  end
@@ -74,10 +77,13 @@ module Google
74
77
  CommitStats.from_grpc @grpc.commit_stats if @grpc.commit_stats
75
78
  end
76
79
 
77
- ##
78
- # @private
79
- # Creates a new Commit responsee instance from a
80
+ # Creates a new `Spanner::CommitResponse` instance from a
80
81
  # `Google::Cloud::Spanner::V1::CommitResponse`.
82
+ #
83
+ # @param grpc [::Google::Cloud::Spanner::V1::CommitResponse]
84
+ # Underlying `V1::CommitResponse` object.
85
+ # @private
86
+ # @return [::Google::Cloud::Spanner::CommitResponse]
81
87
  def self.from_grpc grpc
82
88
  new grpc
83
89
  end
@@ -81,7 +81,7 @@ module Google
81
81
 
82
82
  # Creates a new `Spanner::Instance` instance.
83
83
  # @param grpc [::Google::Cloud::Spanner::Admin::Instance::V1::Instance]
84
- # The protobuf `V1::Instance` underlying object.
84
+ # Underlying `V1::Instance` object.
85
85
  # @param service [::Google::Cloud::Spanner::Service] A `Spanner::Service` reference.
86
86
  # @private
87
87
  def initialize grpc, service
@@ -965,7 +965,7 @@ module Google
965
965
  # Creates a new Instance instance from a
966
966
  # `Google::Cloud::Spanner::Admin::Instance::V1::Instance`.
967
967
  # @param grpc [::Google::Cloud::Spanner::Admin::Instance::V1::Instance]
968
- # The protobuf `V1::Instance` underlying object.
968
+ # Underlying `V1::Instance` object.
969
969
  # @param service [::Google::Cloud::Spanner::Service] A `Spanner::Service` reference.
970
970
  # @private
971
971
  # @return [::Google::Cloud::Spanner::Instance]
@@ -16,6 +16,7 @@
16
16
  require "concurrent"
17
17
  require "google/cloud/spanner/errors"
18
18
  require "google/cloud/spanner/session"
19
+ require "google/cloud/spanner/session_creation_options"
19
20
 
20
21
  module Google
21
22
  module Cloud
@@ -37,7 +38,9 @@ module Google
37
38
  attr_accessor :sessions_in_use
38
39
 
39
40
  # Creates a new Session pool that manages non-multiplexed sessions.
40
- # @param client [::Google::Cloud::Spanner::Client] A `Spanner::Client` reference
41
+ # @param service [::Google::Cloud::Spanner::Service] A `Spanner::Service` reference.
42
+ # @param session_creation_options [::Google::Cloud::Spanner::SessionCreationOptions] Required.
43
+ # Options used for session creation. E.g. session labels.
41
44
  # @param min [::Integer] Min number of sessions to keep
42
45
  # @param max [::Integer] Max number of sessions to keep
43
46
  # @param keepalive [::Numeric] How long after their last usage the sessions can be reclaimed
@@ -46,9 +49,10 @@ module Google
46
49
  # @param threads [::Integer, nil] Number of threads in the thread pool that is used for keepalive and
47
50
  # release session actions. If `nil` the Pool will choose a reasonable default.
48
51
  # @private
49
- def initialize client, min: 10, max: 100, keepalive: 1800,
52
+ def initialize service, session_creation_options, min: 10, max: 100, keepalive: 1800,
50
53
  fail: true, threads: nil
51
- @client = client
54
+ @service = service
55
+ @session_creation_options = session_creation_options
52
56
  @min = min
53
57
  @max = max
54
58
  @keepalive = keepalive
@@ -127,7 +131,7 @@ module Google
127
131
  nil
128
132
  end
129
133
 
130
- def reset
134
+ def reset!
131
135
  close
132
136
  init
133
137
 
@@ -137,6 +141,7 @@ module Google
137
141
 
138
142
  true
139
143
  end
144
+ alias reset reset!
140
145
 
141
146
  def close
142
147
  shutdown
@@ -181,7 +186,7 @@ module Google
181
186
  # init the keepalive task
182
187
  create_keepalive_task!
183
188
  # init session stack
184
- @sessions_available = @client.batch_create_new_sessions @min
189
+ @sessions_available = batch_create_new_sessions @min
185
190
  @sessions_in_use = {}
186
191
  end
187
192
 
@@ -209,7 +214,7 @@ module Google
209
214
  end
210
215
 
211
216
  begin
212
- session = @client.create_new_session
217
+ session = create_new_session
213
218
  rescue StandardError => e
214
219
  @mutex.synchronize do
215
220
  @new_sessions_in_process -= 1
@@ -239,6 +244,60 @@ module Google
239
244
  def future(&)
240
245
  Concurrent::Future.new(executor: @thread_pool, &).execute
241
246
  end
247
+
248
+ # Creates a new `Spanner::Session`.
249
+ # @private
250
+ # @return [::Google::Cloud::Spanner::Session]
251
+ def create_new_session
252
+ ensure_service!
253
+ grpc = @service.create_session(
254
+ @session_creation_options.database_path,
255
+ labels: @session_creation_options.session_labels,
256
+ database_role: @session_creation_options.session_creator_role
257
+ )
258
+
259
+ Session.from_grpc grpc, @service, query_options: @query_options
260
+ end
261
+
262
+ # Creates a batch of new session objects of size `total`.
263
+ # Makes multiple RPCs if necessary. Returns empty array if total is 0.
264
+ # @private
265
+ # @return [::Array<::Google::Cloud::Spanner::Session>]
266
+ def batch_create_new_sessions total
267
+ sessions = []
268
+ remaining = total
269
+ while remaining.positive?
270
+ sessions += batch_create_sessions remaining
271
+ remaining = total - sessions.count
272
+ end
273
+ sessions
274
+ end
275
+
276
+ # Tries to creates a batch of new session objects of size `session_count`.
277
+ # The response may have fewer sessions than requested in the RPC.
278
+ # @private
279
+ # @return [::Array<::Google::Cloud::Spanner::Session>]
280
+ def batch_create_sessions session_count
281
+ ensure_service!
282
+ resp = @service.batch_create_sessions(
283
+ @session_creation_options.database_path,
284
+ session_count,
285
+ labels: @session_creation_options.session_labels,
286
+ database_role: @session_creation_options.session_creator_role
287
+ )
288
+
289
+ resp.session.map do |grpc|
290
+ Session.from_grpc grpc, @service, query_options: @query_options
291
+ end
292
+ end
293
+
294
+ # Raise an error unless an active connection to the service is available.
295
+ # @private
296
+ # @raise [::StandardError]
297
+ # @return [void]
298
+ def ensure_service!
299
+ raise "Must have active connection to service" unless @service
300
+ end
242
301
  end
243
302
  end
244
303
  end