Skip to content

Commit 793b676

Browse files
committed
Merge pull request googleapis#1557 from dhermes/fix-1548-part2
Splitting Bigtable Row into 3 classes based on the mutation type / RPC method used in commit()
2 parents c18e96e + d570aec commit 793b676

File tree

13 files changed

+778
-432
lines changed

13 files changed

+778
-432
lines changed

docs/bigtable-client-intro.rst

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,19 @@ defaults
2121
However, you may over-ride them and these will be used throughout all API
2222
requests made with the ``client`` you create.
2323

24-
Authorization
24+
Configuration
2525
-------------
2626

2727
- For an overview of authentication in ``gcloud-python``,
2828
see :doc:`gcloud-auth`.
2929

3030
- In addition to any authentication configuration, you can also set the
31-
:envvar:`GCLOUD_PROJECT` environment variable for the project you'd like
32-
to interact with. If you are Google App Engine or Google Compute Engine
33-
this will be detected automatically. (Setting this environment
34-
variable is not required, you may instead pass the ``project`` explicitly
35-
when constructing a :class:`Client <gcloud.storage.client.Client>`).
31+
:envvar:`GCLOUD_PROJECT` environment variable for the Google Cloud Console
32+
project you'd like to interact with. If your code is running in Google App
33+
Engine or Google Compute Engine the project will be detected automatically.
34+
(Setting this environment variable is not required, you may instead pass the
35+
``project`` explicitly when constructing a
36+
:class:`Client <gcloud.storage.client.Client>`).
3637

3738
- After configuring your environment, create a
3839
:class:`Client <gcloud.storage.client.Client>`

docs/bigtable-cluster-api.rst

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,13 @@ Check on Current Operation
8585
.. note::
8686

8787
When modifying a cluster (via a `CreateCluster`_, `UpdateCluster`_ or
88-
`UndeleteCluster`_ request), the Bigtable API will return a long-running
89-
`Operation`_. This will be stored on the object after each of
88+
`UndeleteCluster`_ request), the Bigtable API will return a
89+
`long-running operation`_ and a corresponding
90+
:class:`Operation <gcloud.bigtable.cluster.Operation>` object
91+
will be returned by each of
9092
:meth:`create() <gcloud.bigtable.cluster.Cluster.create>`,
9193
:meth:`update() <gcloud.bigtable.cluster.Cluster.update>` and
92-
:meth:`undelete() <gcloud.bigtable.cluster.Cluster.undelete>` are called.
94+
:meth:`undelete() <gcloud.bigtable.cluster.Cluster.undelete>`.
9395

9496
You can check if a long-running operation (for a
9597
:meth:`create() <gcloud.bigtable.cluster.Cluster.create>`,
@@ -176,4 +178,4 @@ Head next to learn about the :doc:`bigtable-table-api`.
176178
.. _ListClusters: https://github.com/GoogleCloudPlatform/cloud-bigtable-client/blob/2aae624081f652427052fb652d3ae43d8ac5bf5a/bigtable-protos/src/main/proto/google/bigtable/admin/cluster/v1/bigtable_cluster_service.proto#L44-L46
177179
.. _GetOperation: https://github.com/GoogleCloudPlatform/cloud-bigtable-client/blob/2aae624081f652427052fb652d3ae43d8ac5bf5a/bigtable-protos/src/main/proto/google/longrunning/operations.proto#L43-L45
178180
.. _UndeleteCluster: https://github.com/GoogleCloudPlatform/cloud-bigtable-client/blob/2aae624081f652427052fb652d3ae43d8ac5bf5a/bigtable-protos/src/main/proto/google/bigtable/admin/cluster/v1/bigtable_cluster_service.proto#L126-L128
179-
.. _Operation: https://github.com/GoogleCloudPlatform/cloud-bigtable-client/blob/2aae624081f652427052fb652d3ae43d8ac5bf5a/bigtable-protos/src/main/proto/google/longrunning/operations.proto#L73-L102
181+
.. _long-running operation: https://github.com/GoogleCloudPlatform/cloud-bigtable-client/blob/2aae624081f652427052fb652d3ae43d8ac5bf5a/bigtable-protos/src/main/proto/google/longrunning/operations.proto#L73-L102

docs/bigtable-data-api.rst

Lines changed: 68 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,11 @@ Cells vs. Columns vs. Column Families
2424
Modifying Data
2525
++++++++++++++
2626

27-
Since data is stored in cells, which are stored in rows, the
28-
:class:`Row <gcloud.bigtable.row.Row>` class is the only class used to
29-
modify (write, update, delete) data in a
27+
Since data is stored in cells, which are stored in rows, we
28+
use the metaphor of a **row** in classes that are used to modify
29+
(write, update, delete) data in a
3030
:class:`Table <gcloud.bigtable.table.Table>`.
3131

32-
Row Factory
33-
-----------
34-
35-
To create a :class:`Row <gcloud.bigtable.row.Row>` object
36-
37-
.. code:: python
38-
39-
row = table.row(row_key)
40-
41-
Unlike the previous string values we've used before, the row key must
42-
be ``bytes``.
43-
4432
Direct vs. Conditional vs. Append
4533
---------------------------------
4634

@@ -49,43 +37,65 @@ There are three ways to modify data in a table, described by the
4937
methods.
5038

5139
* The **direct** way is via `MutateRow`_ which involves simply
52-
adding, overwriting or deleting cells.
40+
adding, overwriting or deleting cells. The
41+
:class:`DirectRow <gcloud.bigtable.row.DirectRow>` class
42+
handles direct mutations.
5343
* The **conditional** way is via `CheckAndMutateRow`_. This method
5444
first checks if some filter is matched in a a given row, then
5545
applies one of two sets of mutations, depending on if a match
5646
occurred or not. (These mutation sets are called the "true
57-
mutations" and "false mutations".)
47+
mutations" and "false mutations".) The
48+
:class:`ConditionalRow <gcloud.bigtable.row.ConditionalRow>` class
49+
handles conditional mutations.
5850
* The **append** way is via `ReadModifyWriteRow`_. This simply
5951
appends (as bytes) or increments (as an integer) data in a presumed
60-
existing cell in a row.
52+
existing cell in a row. The
53+
:class:`AppendRow <gcloud.bigtable.row.AppendRow>` class
54+
handles append mutations.
6155

62-
Building Up Mutations
63-
---------------------
56+
Row Factory
57+
-----------
6458

65-
In all three cases, a set of mutations (or two sets) are built up
66-
on a :class:`Row <gcloud.bigtable.row.Row>` before they are sent of
67-
in a batch via :meth:`commit() <gcloud.bigtable.row.Row.commit>`:
59+
A single factory can be used to create any of the three row types.
60+
To create a :class:`DirectRow <gcloud.bigtable.row.DirectRow>`:
6861

6962
.. code:: python
7063
71-
row.commit()
64+
row = table.row(row_key)
7265
73-
To send **append** mutations in batch, use
74-
:meth:`commit_modifications() <gcloud.bigtable.row.Row.commit_modifications>`:
66+
Unlike the previous string values we've used before, the row key must
67+
be ``bytes``.
68+
69+
To create a :class:`ConditionalRow <gcloud.bigtable.row.ConditionalRow>`,
70+
first create a :class:`RowFilter <gcloud.bigtable.row.RowFilter>` and
71+
then
7572

7673
.. code:: python
7774
78-
row.commit_modifications()
75+
cond_row = table.row(row_key, filter_=filter_)
7976
80-
We have a small set of methods on the :class:`Row <gcloud.bigtable.row.Row>`
81-
to build these mutations up.
77+
To create an :class:`AppendRow <gcloud.bigtable.row.AppendRow>`
78+
79+
.. code:: python
80+
81+
append_row = table.row(row_key, append=True)
82+
83+
Building Up Mutations
84+
---------------------
85+
86+
In all three cases, a set of mutations (or two sets) are built up
87+
on a row before they are sent of in a batch via
88+
89+
.. code:: python
90+
91+
row.commit()
8292
8393
Direct Mutations
8494
----------------
8595

8696
Direct mutations can be added via one of four methods
8797

88-
* :meth:`set_cell() <gcloud.bigtable.row.Row.set_cell>` allows a
98+
* :meth:`set_cell() <gcloud.bigtable.row.DirectRow.set_cell>` allows a
8999
single value to be written to a column
90100

91101
.. code:: python
@@ -97,9 +107,9 @@ Direct mutations can be added via one of four methods
97107
Bigtable server will be used when the cell is stored.
98108

99109
The value can either by bytes or an integer (which will be converted to
100-
bytes as an unsigned 64-bit integer).
110+
bytes as a signed 64-bit integer).
101111

102-
* :meth:`delete_cell() <gcloud.bigtable.row.Row.delete_cell>` deletes
112+
* :meth:`delete_cell() <gcloud.bigtable.row.DirectRow.delete_cell>` deletes
103113
all cells (i.e. for all timestamps) in a given column
104114

105115
.. code:: python
@@ -117,8 +127,9 @@ Direct mutations can be added via one of four methods
117127
row.delete_cell(column_family_id, column,
118128
time_range=time_range)
119129
120-
* :meth:`delete_cells() <gcloud.bigtable.row.Row.delete_cells>` does
121-
the same thing as :meth:`delete_cell() <gcloud.bigtable.row.Row.delete_cell>`
130+
* :meth:`delete_cells() <gcloud.bigtable.row.DirectRow.delete_cells>` does
131+
the same thing as
132+
:meth:`delete_cell() <gcloud.bigtable.row.DirectRow.delete_cell>`
122133
but accepts a list of columns in a column family rather than a single one.
123134

124135
.. code:: python
@@ -127,15 +138,16 @@ Direct mutations can be added via one of four methods
127138
time_range=time_range)
128139
129140
In addition, if we want to delete cells from every column in a column family,
130-
the special :attr:`ALL_COLUMNS <gcloud.bigtable.row.Row.ALL_COLUMNS>` value
131-
can be used
141+
the special :attr:`ALL_COLUMNS <gcloud.bigtable.row.DirectRow.ALL_COLUMNS>`
142+
value can be used
132143

133144
.. code:: python
134145
135-
row.delete_cells(column_family_id, Row.ALL_COLUMNS,
146+
row.delete_cells(column_family_id, row.ALL_COLUMNS,
136147
time_range=time_range)
137148
138-
* :meth:`delete() <gcloud.bigtable.row.Row.delete>` will delete the entire row
149+
* :meth:`delete() <gcloud.bigtable.row.DirectRow.delete>` will delete the
150+
entire row
139151

140152
.. code:: python
141153
@@ -145,57 +157,42 @@ Conditional Mutations
145157
---------------------
146158

147159
Making **conditional** modifications is essentially identical
148-
to **direct** modifications, but we need to specify a filter to match
149-
against in the row:
160+
to **direct** modifications: it uses the exact same methods
161+
to accumulate mutations.
150162

151-
.. code:: python
152-
153-
row = table.row(row_key, filter_=filter_val)
154-
155-
See the :class:`Row <gcloud.bigtable.row.Row>` class for more information
156-
about acceptable values for ``filter_``.
157-
158-
The only other difference from **direct** modifications are that each mutation
159-
added must specify a ``state``: will the mutation be applied if the filter
160-
matches or if it fails to match.
163+
However, each mutation added must specify a ``state``: will the mutation be
164+
applied if the filter matches or if it fails to match.
161165

162166
For example:
163167

164168
.. code:: python
165169
166-
row.set_cell(column_family_id, column, value,
167-
timestamp=timestamp, state=True)
170+
cond_row.set_cell(column_family_id, column, value,
171+
timestamp=timestamp, state=True)
168172
169173
will add to the set of true mutations.
170174

171-
.. note::
172-
173-
If ``state`` is passed when no ``filter_`` is set on a
174-
:class:`Row <gcloud.bigtable.row.Row>`, adding the mutation will fail.
175-
Similarly, if no ``state`` is passed when a ``filter_`` has been set,
176-
adding the mutation will fail.
177-
178175
Append Mutations
179176
----------------
180177

181178
Append mutations can be added via one of two methods
182179

183-
* :meth:`append_cell_value() <gcloud.bigtable.row.Row.append_cell_value>`
180+
* :meth:`append_cell_value() <gcloud.bigtable.row.AppendRow.append_cell_value>`
184181
appends a bytes value to an existing cell:
185182

186183
.. code:: python
187184
188-
row.append_cell_value(column_family_id, column, bytes_value)
185+
append_row.append_cell_value(column_family_id, column, bytes_value)
189186
190-
* :meth:`increment_cell_value() <gcloud.bigtable.row.Row.increment_cell_value>`
187+
* :meth:`increment_cell_value() <gcloud.bigtable.row.AppendRow.increment_cell_value>`
191188
increments an integer value in an existing cell:
192189

193190
.. code:: python
194191
195-
row.increment_cell_value(column_family_id, column, int_value)
192+
append_row.increment_cell_value(column_family_id, column, int_value)
196193
197194
Since only bytes are stored in a cell, the cell value is decoded as
198-
an unsigned 64-bit integer before being incremented. (This happens on
195+
a signed 64-bit integer before being incremented. (This happens on
199196
the Google Cloud Bigtable server, not in the library.)
200197

201198
Notice that no timestamp was specified. This is because **append** mutations
@@ -208,18 +205,10 @@ Starting Fresh
208205
--------------
209206

210207
If accumulated mutations need to be dropped, use
211-
:meth:`clear_mutations() <gcloud.bigtable.row.Row.clear_mutations>`
212-
213-
.. code:: python
214-
215-
row.clear_mutations()
216-
217-
To clear **append** mutations, use
218-
:meth:`clear_modification_rules() <gcloud.bigtable.row.Row.clear_modification_rules>`
219208

220209
.. code:: python
221210
222-
row.clear_modification_rules()
211+
row.clear()
223212
224213
Reading Data
225214
++++++++++++
@@ -260,19 +249,20 @@ To make a `ReadRows`_ API request for a single row key, use
260249
>>> cell.timestamp
261250
datetime.datetime(2016, 2, 27, 3, 41, 18, 122823, tzinfo=<UTC>)
262251
263-
Rather than returning a :class:`Row <gcloud.bigtable.row.Row>`, this method
264-
returns a :class:`PartialRowData <gcloud.bigtable.row_data.PartialRowData>`
252+
Rather than returning a :class:`DirectRow <gcloud.bigtable.row.DirectRow>`
253+
or similar class, this method returns a
254+
:class:`PartialRowData <gcloud.bigtable.row_data.PartialRowData>`
265255
instance. This class is used for reading and parsing data rather than for
266-
modifying data (as :class:`Row <gcloud.bigtable.row.Row>` is).
256+
modifying data (as :class:`DirectRow <gcloud.bigtable.row.DirectRow>` is).
267257

268-
A filter can also be applied to the
258+
A filter can also be applied to the results:
269259

270260
.. code:: python
271261
272262
row_data = table.read_row(row_key, filter_=filter_val)
273263
274264
The allowable ``filter_`` values are the same as those used for a
275-
:class:`Row <gcloud.bigtable.row.Row>` with **conditional** mutations. For
265+
:class:`ConditionalRow <gcloud.bigtable.row.ConditionalRow>`. For
276266
more information, see the
277267
:meth:`Table.read_row() <gcloud.bigtable.table.Table.read_row>` documentation.
278268

docs/bigtable-row.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ Bigtable Row
22
============
33

44
It is possible to use a :class:`RowFilter <gcloud.bigtable.row.RowFilter>`
5-
when adding mutations to a :class:`Row <gcloud.bigtable.row.Row>` and when
5+
when adding mutations to a
6+
:class:`ConditionalRow <gcloud.bigtable.row.ConditionalRow>` and when
67
reading row data with :meth:`read_row() <gcloud.bigtable.table.Table.read_row>`
78
:meth:`read_rows() <gcloud.bigtable.table.Table.read_rows>`.
89

gcloud/bigtable/happybase/table.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -603,12 +603,12 @@ def counter_inc(self, row, column, value=1):
603603
:rtype: int
604604
:returns: Counter value after incrementing.
605605
"""
606-
row = self._low_level_table.row(row)
606+
row = self._low_level_table.row(row, append=True)
607607
if isinstance(column, six.binary_type):
608608
column = column.decode('utf-8')
609609
column_family_id, column_qualifier = column.split(':')
610610
row.increment_cell_value(column_family_id, column_qualifier, value)
611-
# See row.commit_modifications() will return a dictionary:
611+
# See AppendRow.commit() will return a dictionary:
612612
# {
613613
# u'col-fam-id': {
614614
# b'col-name1': [
@@ -618,7 +618,7 @@ def counter_inc(self, row, column, value=1):
618618
# ...
619619
# },
620620
# }
621-
modified_cells = row.commit_modifications()
621+
modified_cells = row.commit()
622622
# Get the cells in the modified column,
623623
column_cells = modified_cells[column_family_id][column_qualifier]
624624
# Make sure there is exactly one cell in the column.

gcloud/bigtable/happybase/test_table.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -871,10 +871,12 @@ def _counter_inc_helper(self, row, column, value, commit_result):
871871
table = self._makeOne(name, connection)
872872
# Mock the return values.
873873
table._low_level_table = _MockLowLevelTable()
874-
table._low_level_table.row_values[row] = _MockLowLevelRow(
874+
table._low_level_table.row_values[row] = row_obj = _MockLowLevelRow(
875875
row, commit_result=commit_result)
876876

877+
self.assertFalse(row_obj._append)
877878
result = table.counter_inc(row, column, value=value)
879+
self.assertTrue(row_obj._append)
878880

879881
incremented_value = value + _MockLowLevelRow.COUNTER_DEFAULT
880882
self.assertEqual(result, incremented_value)
@@ -1431,8 +1433,10 @@ def list_column_families(self):
14311433
self.list_column_families_calls += 1
14321434
return self.column_families
14331435

1434-
def row(self, row_key):
1435-
return self.row_values[row_key]
1436+
def row(self, row_key, append=None):
1437+
result = self.row_values[row_key]
1438+
result._append = append
1439+
return result
14361440

14371441
def read_row(self, *args, **kwargs):
14381442
self.read_row_calls.append((args, kwargs))
@@ -1449,6 +1453,7 @@ class _MockLowLevelRow(object):
14491453

14501454
def __init__(self, row_key, commit_result=None):
14511455
self.row_key = row_key
1456+
self._append = False
14521457
self.counts = {}
14531458
self.commit_result = commit_result
14541459

@@ -1457,7 +1462,7 @@ def increment_cell_value(self, column_family_id, column, int_value):
14571462
self.COUNTER_DEFAULT)
14581463
self.counts[(column_family_id, column)] = count + int_value
14591464

1460-
def commit_modifications(self):
1465+
def commit(self):
14611466
return self.commit_result
14621467

14631468

0 commit comments

Comments
 (0)