Skip to content

Commit f09726a

Browse files
chore: add multiplex session creation plumbing
1 parent 40264d0 commit f09726a

10 files changed

Lines changed: 235 additions & 61 deletions

File tree

google-cloud-spanner/.rubocop.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ AllCops:
1111
- "vendor/**/*"
1212
- "acceptance/data/protos/**/*"
1313

14-
Documentation:
14+
Style/Documentation:
1515
Enabled: false
1616

1717
Metrics/BlockLength:

google-cloud-spanner/Gemfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ gem "minitest-rg", "~> 5.3"
1919
gem "rake"
2020
gem "redcarpet", "~> 3.0"
2121
gem "simplecov", "~> 0.22"
22+
gem "solargraph", group: :development, require: false
2223
gem "yard", "~> 0.9"
23-
gem "yard-doctest", "~> 0.1.17"
24+
gem "yard-doctest", "~> 0.1.17", group: :development

google-cloud-spanner/acceptance/spanner/backup_operations_test.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
it "list backup operations" do
2525
skip if emulator_enabled?
2626

27+
# @type [::Google::Cloud::Spanner::Instance]
2728
instance = spanner.instance instance_id
2829
_(instance).wont_be :nil?
2930

google-cloud-spanner/lib/google/cloud/spanner/batch_client.rb

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,18 @@ module Spanner
6363
# new_partition
6464
#
6565
class BatchClient
66-
##
67-
# @private Creates a new Spanner BatchClient instance.
66+
# Creates a new Spanner BatchClient instance.
67+
# @param project [::Google::Cloud::Spanner::Project] A `Spanner::Project` ref.
68+
# @param instance_id [::String] Instance id, e.g. `"my-instance"`.
69+
# @param database_id [::String] Database id, e.g. `"my-database"`.
70+
# @param session_labels [::Hash, nil] Optional. The labels to be applied to all sessions
71+
# created by the client. Example: `"team" => "billing-service"`.
72+
# @param query_options [::Hash, nil] Optional. A hash of values to specify the custom
73+
# query options for executing SQL query. Example parameter `:optimizer_version`.
74+
# @param directed_read_options [::Hash, nil] Optional. Client options used to set
75+
# the `directed_read_options` for all ReadRequests and ExecuteSqlRequests.
76+
# Converts to `V1::DirectedReadOptions`. Example option: `:exclude_replicas`.
77+
# @private
6878
def initialize project, instance_id, database_id, session_labels: nil,
6979
query_options: nil, directed_read_options: nil
7080
@project = project
@@ -404,15 +414,18 @@ def inspect
404414

405415
protected
406416

407-
##
408-
# @private Raise an error unless an active connection to the service is
417+
# Raise an error unless an active connection to the service is
409418
# available.
419+
# @private
420+
# @raise [StandardError]
421+
# @return nil
410422
def ensure_service!
411423
raise "Must have active connection to service" unless @project.service
412424
end
413425

414-
##
415426
# New session for each use.
427+
# @private
428+
# @return [::Google::Cloud::Spanner::Session]
416429
def session
417430
ensure_service!
418431
grpc = @project.service.create_session \

google-cloud-spanner/lib/google/cloud/spanner/client.rb

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,26 @@ module Spanner
5151
# end
5252
#
5353
class Client
54-
##
54+
# A semi-arbitrary constant for thread-wide global parameter name
5555
# @private
5656
IS_TRANSACTION_RUNNING_KEY = "ruby_spanner_is_transaction_running".freeze
5757

58-
##
59-
# @private Creates a new Spanner Client instance.
58+
# Creates a new Spanner Client instance.
59+
# @param project [::Google::Cloud::Spanner::Project] A `Spanner::Project` ref.
60+
# @param instance_id [::String] Instance id, e.g. `"my-instance"`.
61+
# @param database_id [::String] Database id, e.g. `"my-database"`.
62+
# @param session_labels [::Hash, nil] Optional. The labels to be applied to all sessions
63+
# created by the client. Example: `"team" => "billing-service"`.
64+
# @param pool_opts [::Hash] Optional. `Spanner::Pool` creation options.
65+
# Example parameter: `:keepalive`.
66+
# @param query_options [::Hash, nil] Optional. A hash of values to specify the custom
67+
# query options for executing SQL query. Example parameter `:optimizer_version`.
68+
# @param database_role [::String, nil] Optional. The Spanner session creator role.
69+
# Example: `analyst`
70+
# @param directed_read_options [::Hash, nil] Optional. Client options used to set
71+
# the `directed_read_options` for all ReadRequests and ExecuteSqlRequests.
72+
# Converts to `V1::DirectedReadOptions`. Example option: `:exclude_replicas`.
73+
# @private
6074
def initialize project, instance_id, database_id, session_labels: nil,
6175
pool_opts: {}, query_options: nil, database_role: nil,
6276
directed_read_options: nil
@@ -89,7 +103,7 @@ def database_id
89103
end
90104

91105
# The Spanner project connected to.
92-
# @return [Project]
106+
# @return [::Google::Cloud::Spanner::Project]
93107
def project
94108
@project
95109
end
@@ -2419,17 +2433,21 @@ def reset
24192433
@pool.reset
24202434
end
24212435

2422-
##
2436+
# Creates a new Session objece.
2437+
# @param multiplexed [::Boolean] Optional. Default to `false`.
2438+
# If `true`, specifies a multiplexed session.
24232439
# @private
2424-
# Creates a new session object every time.
2425-
def create_new_session
2440+
# @return [::Google::Cloud::Spanner::Session]
2441+
def create_new_session multiplexed: false
24262442
ensure_service!
24272443
grpc = @project.service.create_session \
24282444
Admin::Database::V1::DatabaseAdmin::Paths.database_path(
24292445
project: project_id, instance: instance_id, database: database_id
24302446
),
24312447
labels: @session_labels,
2432-
database_role: @database_role
2448+
database_role: @database_role,
2449+
multiplexed: multiplexed
2450+
24332451
Session.from_grpc grpc, @project.service, query_options: @query_options
24342452
end
24352453

google-cloud-spanner/lib/google/cloud/spanner/pool.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ class Pool
3636
# and `Session` objects as values.
3737
attr_accessor :sessions_in_use
3838

39+
# Creates a new Session pool that manages non-multiplexed sessions.
40+
# @param client [::Google::Cloud::Spanner::Client] A `Spanner::Client` reference
41+
# @param min [::Integer] Min number of sessions to keep
42+
# @param max [::Integer] Max number of sessions to keep
43+
# @param keepalive [::Numeric] How long after their last usage the sessions can be reclaimed
44+
# @param fail [::Boolean] If `true` the pool will raise `SessionLimitError` if number of new sessions
45+
# needed is more that can be created due to the `max` parameter. If `false` it will wait instead.
46+
# @param threads [::Integer, nil] Number of threads in the thread pool that is used for keepalive and
47+
# release session actions. If `nil` the Pool will choose a reasonable default.
48+
# @private
3949
def initialize client, min: 10, max: 100, keepalive: 1800,
4050
fail: true, threads: nil
4151
@client = client
@@ -52,6 +62,11 @@ def initialize client, min: 10, max: 100, keepalive: 1800,
5262
init
5363
end
5464

65+
# Provides a session for running an operation
66+
# @yield session Session a client can use to run an operation
67+
# @yieldparam [::Google::Cloud::Spanner::Session] `Spanner::Session` to run an operation
68+
# @private
69+
# @return [nil]
5570
def with_session
5671
session = checkout_session
5772
begin

google-cloud-spanner/lib/google/cloud/spanner/project.rb

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,22 @@ module Spanner
6666
# end
6767
#
6868
class Project
69-
##
70-
# @private The Service object.
71-
attr_accessor :service, :query_options
69+
# The `Spanner::Service` reference.
70+
# @private
71+
# @return [::Google::Cloud::Spanner::Service]
72+
attr_accessor :service
7273

73-
##
74-
# @private Creates a new Spanner Project instance.
74+
# A hash of values to specify the custom query options for executing SQL query.
75+
# Example option: `:optimizer_version`.
76+
# @private
77+
# @return [::Hash, nil]
78+
attr_accessor :query_options
79+
80+
# Creates a new Spanner Project instance.
81+
# @param service [::Google::Cloud::Spanner::Service] The `Spanner::Service` ref.
82+
# @param query_options [::Hash, nil] Optional. A hash of values to specify the custom
83+
# query options for executing SQL query. Example option: `:optimizer_version`.
84+
# @private
7585
def initialize service, query_options: nil
7686
@service = service
7787
@query_options = query_options
@@ -80,6 +90,8 @@ def initialize service, query_options: nil
8090
##
8191
# The identifier for the Cloud Spanner project.
8292
#
93+
# @return [::String]
94+
#
8395
# @example
8496
# require "google/cloud"
8597
#

google-cloud-spanner/lib/google/cloud/spanner/service.rb

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,18 @@ class Service
4343
RST_STREAM_INTERNAL_ERROR = "Received RST_STREAM".freeze
4444
EOS_INTERNAL_ERROR = "Received unexpected EOS on DATA frame from server".freeze
4545

46-
##
47-
# Creates a new Service instance.
46+
# Creates a new `Spanner::Service` instance.
47+
# @param project [::String] The project id to use
48+
# @param credentials [::Symbol, ::Google::Auth::Credentials] Credentials
49+
# @param quota_project [::String, nil] Optional. The quota project id to use
50+
# @param host [::String, nil] Optional. The endpoint override.
51+
# @param timeout [::Numeric, nil] Optional. Timeout for Gapic client.
52+
# @param lib_name [::String, nil] Optional. Library name for headers.
53+
# @param lib_version [::String, nil] Optional. Library version for headers.
54+
# @param enable_leader_aware_routing [::Boolean, nil] Optional. Whether Leader
55+
# Aware Routing should be enabled.
56+
# @param universe_domain [::String, nil] Optional. The domain of the universe to connect to.
57+
# @private
4858
def initialize project, credentials, quota_project: nil,
4959
host: nil, timeout: nil, lib_name: nil, lib_version: nil,
5060
enable_leader_aware_routing: nil, universe_domain: nil
@@ -82,6 +92,8 @@ def chan_creds
8292
GRPC::Core::CallCredentials.new credentials.client.updater_proc
8393
end
8494

95+
# `V1::Spanner::Client` or a mock.
96+
# @return [::Google::Cloud::Spanner::V1::Spanner::Client]
8597
def service
8698
return mocked_service if mocked_service
8799
@service ||=
@@ -329,13 +341,41 @@ def get_session session_name, call_options: nil
329341
service.get_session({ name: session_name }, opts)
330342
end
331343

344+
# Creates a new Spanner session.
345+
# This creates a `V1::Session` protobuf object not wrapped in `Spanner::Session`.
346+
#
347+
# @param database_name [::String] The full name of the database.
348+
# @param labels [::Hash, nil] Optional. The labels to be applied to all sessions
349+
# created by the client. Example: `"team" => "billing-service"`.
350+
# @param call_options [::Hash, nil] Optional. A hash of values to specify the custom
351+
# call options. Example option `:timeout`.
352+
# @param database_role [::String, nil] Optional. The Spanner session creator role.
353+
# Example: `analyst`.
354+
# @param multiplexed [::Boolean] Optional. Default to `false`.
355+
# If `true`, specifies a multiplexed session.
356+
# @return [::Google::Cloud::Spanner::V1::Session]
357+
# @private
332358
def create_session database_name, labels: nil,
333-
call_options: nil, database_role: nil
359+
call_options: nil, database_role: nil,
360+
multiplexed: false
334361
route_to_leader = LARHeaders.create_session
335-
opts = default_options session_name: database_name,
336-
call_options: call_options,
337-
route_to_leader: route_to_leader
338-
session = V1::Session.new labels: labels, creator_role: database_role if labels || database_role
362+
opts = default_options(
363+
session_name: database_name,
364+
call_options: call_options,
365+
route_to_leader: route_to_leader
366+
)
367+
368+
# check if we need a session object in request or server defaults would work.
369+
params_diff_from_default = !(labels.nil? && database_role.nil? && !multiplexed)
370+
371+
if params_diff_from_default
372+
session = V1::Session.new(
373+
labels: labels,
374+
creator_role: database_role,
375+
multiplexed: multiplexed
376+
)
377+
end
378+
339379
service.create_session(
340380
{ database: database_name, session: session }, opts
341381
)
@@ -464,6 +504,29 @@ def partition_query session_name, sql, transaction, params: nil,
464504
service.partition_query request, opts
465505
end
466506

507+
# Commits a transaction. Can be a predefined (`transaction_id`) transaction
508+
# or a single-use created for this request. The request includes the mutations to be
509+
# applied to rows in the database.
510+
#
511+
# @param session_name [::String]
512+
# Required. The session in which the transaction to be committed is running.
513+
# @param mutations [::Array<::Google::Cloud::Spanner::V1::Mutation>] Optional.
514+
# The mutations to be executed when this transaction commits. All
515+
# mutations are applied atomically, in the order they appear in
516+
# this list. Defaults to an empty array.
517+
# @param transaction_id [::String, nil] Optional.
518+
# Commit a previously-started transaction. If nil, a new single-use transation will be used.
519+
# @param exclude_txn_from_change_streams [::Boolean] Optional. Defaults to `false`.
520+
# When `exclude_txn_from_change_streams` is set to `true`, it prevents read
521+
# or write transactions from being tracked in change streams.
522+
# @param commit_options [::Hash, nil] Optional. A hash of commit options.
523+
# Example option: `:return_commit_stats`.
524+
# @param request_options [::Hash, nil] Optional. Common request options.
525+
# Example option: `:priority`.
526+
# @param call_options [::Hash, nil] Optional. A hash of values to specify the custom
527+
# call options. Example option `:timeout`.
528+
# @return [::Google::Cloud::Spanner::V1::CommitResponse]
529+
# @private
467530
def commit session_name, mutations = [],
468531
transaction_id: nil, exclude_txn_from_change_streams: false,
469532
commit_options: nil, request_options: nil, call_options: nil
@@ -485,10 +548,16 @@ def commit session_name, mutations = [],
485548
}
486549

487550
request = add_commit_options request, commit_options
488-
551+
# request is a hash equivalent of `::Google::Cloud::Spanner::V1::CommitRequest`
489552
service.commit request, opts
490553
end
491554

555+
# Merges commit options hash to a hash representing a `V1::CommitRequest`.
556+
# @param request [::Hash] A `::Google::Cloud::Spanner::V1::CommitRequest` in a hash form.
557+
# @param commit_options [::Hash, nil] Optional. A hash of commit options.
558+
# Example option: `:return_commit_stats`.
559+
# @return [::Hash] An enriched `::Google::Cloud::Spanner::V1::CommitRequest` in a hash form.
560+
# @private
492561
def add_commit_options request, commit_options
493562
if commit_options
494563
if commit_options.key? :return_commit_stats

0 commit comments

Comments
 (0)