google-cloud-bigtable 2.12.0 → 2.12.1

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: d532accadd2ab9206259a83bc75b52a460d8e15e2253c81ee9f7124fdefbfa83
4
- data.tar.gz: d1bee0fb74cf2522095176d827323731d347e6a60575f3b2beb1f664879aa616
3
+ metadata.gz: '0587331e991797446cc8d8b1893fb724de88f47f870ef27417f2e4aea60fe375'
4
+ data.tar.gz: e05005b9b777488a397aa8ef55a62c43b3e824856bd0b43e9994ce3790b16be2
5
5
  SHA512:
6
- metadata.gz: 3c7164cb81c2f57bbfadb426cc1038fe1fe817cb102e6305e468c41034e0f081e4e13183c6490b49c93203b8390b4415e8288e84a3c2a330beb2a0f4b80b0fae
7
- data.tar.gz: e8c61bb38bc9a0297cbf2954323239bd4ebd95a4578627b1a1707683b7e40b35e50bfd3e5f2dd8d90389330cad1562e88cd0de946006a71500db0060d4d00143
6
+ metadata.gz: 3bf97892a0fdc0da3d9203424add9273451a3239056adc5fc9eb8ac70c4b6a30e7b2e1430baf4cbd16237833d26aa29982b4de24f607dbd5f0d83ef7114bf6be
7
+ data.tar.gz: f1b805236765623233a094af1b79572e7693363cf32346a9632559a6826fe66f3c9ed754fb8326344fbdb3dd00af75f080142fc6dd315deff8eba19f1079e9b5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Release History
2
2
 
3
+ ### 2.12.1 (2025-08-12)
4
+
5
+ #### Bug Fixes
6
+
7
+ * Fix mutate rows logic to handle errors ([#30766](https://github.com/googleapis/google-cloud-ruby/issues/30766))
8
+
3
9
  ### 2.12.0 (2025-02-25)
4
10
 
5
11
  #### Features
@@ -94,12 +94,23 @@ module Google
94
94
  # or if family name or column qualifier are empty
95
95
  #
96
96
  def validate_new_row
97
- raise_if row.key, "A new row cannot have existing state"
98
- raise_if chunk.row_key.empty?, "A row key must be set"
99
- raise_if chunk.reset_row, "A new row cannot be reset"
100
- raise_if last_key == chunk.row_key, "A commit happened but the same key followed"
101
- raise_if chunk.family_name.nil?, "A family must be set"
102
- raise_if chunk.qualifier.nil?, "A column qualifier must be set"
97
+ validations = [
98
+ [row.key, "A new row cannot have existing state"],
99
+ [chunk.row_key.empty?, "A row key must be set"],
100
+ [chunk.reset_row, "A new row cannot be reset"],
101
+ [last_key == chunk.row_key, "A commit happened but the same key followed"],
102
+ [
103
+ last_key && chunk.row_key < last_key,
104
+ "Out of order row key, must be strictly increasing. " \
105
+ "New key: '#{chunk.row_key}', Previous key: '#{last_key}'"
106
+ ],
107
+ [chunk.family_name.nil?, "A family must be set"],
108
+ [chunk.qualifier.nil?, "A column qualifier must be set"]
109
+ ]
110
+
111
+ validations.each do |condition, message|
112
+ raise_if condition, message
113
+ end
103
114
  end
104
115
 
105
116
  ##
@@ -39,6 +39,10 @@ module Google
39
39
  RETRY_LIMIT = 3
40
40
 
41
41
  # @private
42
+ # The prefix for routing cookies. Used to dynamically find cookie
43
+ # headers in metadata.
44
+ COOKIE_KEY_PREFIX = "x-goog-cbt-cookie"
45
+
42
46
  #
43
47
  # Creates a mutate rows instance.
44
48
  #
@@ -57,18 +61,20 @@ module Google
57
61
  #
58
62
  def apply_mutations
59
63
  @req_entries = @entries.map(&:to_grpc)
60
- statuses = mutate_rows @req_entries
64
+ statuses, delay, cookies = mutate_rows @req_entries
61
65
 
62
- # Collects retryable mutations indices.
63
66
  indices = statuses.each_with_object [] do |e, r|
64
67
  r << e.index if @entries[e.index].retryable? && RETRYABLE_CODES[e.status.code]
65
68
  end
66
69
 
67
70
  return statuses if indices.empty?
68
71
 
69
- (RETRY_LIMIT - 1).times do
72
+ RETRY_LIMIT.times do
70
73
  break if indices.empty?
71
- indices = retry_entries statuses, indices
74
+
75
+ sleep delay if delay
76
+
77
+ indices, delay, cookies = retry_entries statuses, indices, cookies
72
78
  end
73
79
 
74
80
  statuses
@@ -80,13 +86,35 @@ module Google
80
86
  # Mutates rows.
81
87
  #
82
88
  # @param entries [Array<Google::Cloud::Bigtable::MutationEntry>]
83
- # @return [Array<Google::Cloud::Bigtable::V2::MutateRowsResponse::Entry>]
89
+ # @param cookies [Hash]
90
+ # @return [Array<Google::Cloud::Bigtable::V2::MutateRowsResponse::Entry>, Float|nil, Hash]
84
91
  #
85
- def mutate_rows entries
86
- response = @table.service.mutate_rows @table.path, entries, app_profile_id: @table.app_profile_id
87
- response.each_with_object [] do |res, statuses|
88
- statuses.concat res.entries
92
+ def mutate_rows entries, cookies = {}
93
+ call_options = Gapic::CallOptions.new(metadata: cookies) unless cookies.empty?
94
+
95
+ response = @table.service.mutate_rows(
96
+ @table.path,
97
+ entries,
98
+ app_profile_id: @table.app_profile_id,
99
+ call_options: call_options
100
+ )
101
+ [response.flat_map(&:entries), nil, cookies]
102
+ rescue GRPC::BadStatus => e
103
+ info = e.status_details.find { |d| d.is_a? Google::Rpc::RetryInfo }
104
+ delay = if info&.retry_delay
105
+ info.retry_delay.seconds + (info.retry_delay.nanos / 1_000_000_000.0)
106
+ end
107
+
108
+ cookies.merge!(e.metadata.select { |k, _| k.start_with? COOKIE_KEY_PREFIX })
109
+
110
+ status = Google::Rpc::Status.new code: e.code, message: e.message
111
+ statuses = entries.map.with_index do |_, i|
112
+ Google::Cloud::Bigtable::V2::MutateRowsResponse::Entry.new(
113
+ index: i,
114
+ status: status
115
+ )
89
116
  end
117
+ [statuses, delay, cookies]
90
118
  end
91
119
 
92
120
  ##
@@ -94,18 +122,19 @@ module Google
94
122
  #
95
123
  # @param statuses [Array<Google::Cloud::Bigtable::V2::MutateRowsResponse::Entry>]
96
124
  # @param indices [Array<Integer>]
97
- # Retry entries position mapping list
98
- # @return [Array<Integer>]
99
- # New list of failed entries positions
125
+ # @param cookies [Hash]
126
+ # @return [Array<Integer>, Float|nil, Hash]
100
127
  #
101
- def retry_entries statuses, indices
128
+ def retry_entries statuses, indices, cookies
102
129
  entries = indices.map { |i| @req_entries[i] }
103
- retry_statuses = mutate_rows entries
130
+ retry_statuses, delay, cookies = mutate_rows entries, cookies
104
131
 
105
- retry_statuses.each_with_object [] do |e, next_indices|
106
- next_indices << indices[e.index] if RETRYABLE_CODES[e.status.code]
107
- statuses[indices[e.index]].status = e.status
132
+ next_indices = retry_statuses.each_with_object [] do |e, list|
133
+ next_index = indices[e.index]
134
+ statuses[next_index].status = e.status
135
+ list << next_index if RETRYABLE_CODES[e.status.code]
108
136
  end
137
+ [next_indices, delay, cookies]
109
138
  end
110
139
  end
111
140
  end
@@ -92,6 +92,10 @@ module Google
92
92
  yield row
93
93
  @rows_count += 1
94
94
  end
95
+
96
+ if res.last_scanned_row_key && !res.last_scanned_row_key.empty?
97
+ @chunk_processor.last_key = res.last_scanned_row_key
98
+ end
95
99
  end
96
100
 
97
101
  @chunk_processor.validate_last_row_complete
@@ -689,14 +689,13 @@ module Google
689
689
  )
690
690
  end
691
691
 
692
- def mutate_rows table_name, entries, app_profile_id: nil
693
- client(table_name, app_profile_id).mutate_rows(
694
- **{
695
- table_name: table_name,
696
- app_profile_id: app_profile_id,
697
- entries: entries
698
- }.compact
699
- )
692
+ def mutate_rows table_name, entries, app_profile_id: nil, call_options: nil
693
+ request = {
694
+ table_name: table_name,
695
+ app_profile_id: app_profile_id,
696
+ entries: entries
697
+ }.compact
698
+ client(table_name, app_profile_id).mutate_rows request, call_options
700
699
  end
701
700
 
702
701
  def check_and_mutate_row table_name,
@@ -16,7 +16,7 @@
16
16
  module Google
17
17
  module Cloud
18
18
  module Bigtable
19
- VERSION = "2.12.0".freeze
19
+ VERSION = "2.12.1".freeze
20
20
  end
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-cloud-bigtable
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.0
4
+ version: 2.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Google LLC
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-02-25 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: concurrent-ruby
@@ -149,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
149
  - !ruby/object:Gem::Version
150
150
  version: '0'
151
151
  requirements: []
152
- rubygems_version: 3.6.5
152
+ rubygems_version: 3.6.9
153
153
  specification_version: 4
154
154
  summary: API Client library for Cloud Bigtable API
155
155
  test_files: []