Uh oh!
There was an error while loading. Please reload this page.
Implement multi-use snapshots - #3615
Conversation
dhermes
left a comment
There was a problem hiding this comment.
No real issues, just cosmetics.
Sorry for the delay in review.
| def snapshot(self, read_timestamp=None, min_read_timestamp=None, | ||
| max_staleness=None, exact_staleness=None): | ||
| def snapshot(self, **kw): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| if len(flagged) > 1: | ||
| raise ValueError("Supply zero or one options.") | ||
| if multi_use and (min_read_timestamp or max_staleness): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| if multi_use and (min_read_timestamp or max_staleness): | ||
| raise ValueError( | ||
| "'multi_use' is incompatile with " |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| self._resume_token = response.resume_token | ||
| if self._metadata is None: # first response | ||
| # XXX: copy implicit txn ID to snapshot, if present. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| self.assertEqual(options.kwargs['metadata'], | ||
| [('google-cloud-resource-prefix', database.name)]) | ||
| def test_execute_sql_wo_mulit_use(self): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| return Value(list_value=_make_list_value_pb(values)) | ||
| @staticmethod | ||
| def _makeResultSetMetadata(fields=(), transaction_id=None): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| # limitations under the License. | ||
| import mock |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
ad62692 to
d445a73Compare| def test_multiuse_snapshot_read_isolation_exact_staleness(self): | ||
| import time | ||
| from datetime import timedelta |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
tseaver
commented
Jul 19, 2017
I haven't added any: I had to rebase to fix the conflicts with your |
| return StreamedResultSet(iterator) | ||
| def execute_sql(self, sql, params=None, param_types=None, query_mode=None, | ||
| resume_token=b''): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| ``exact_staleness`` old. | ||
| :type multi_use: :class:`bool` | ||
| :param multi_use: If true, the first read operation creates a read-only |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| if self._multi_use: | ||
| return StreamedResultSet(iterator, source=self) | ||
| else: | ||
| return StreamedResultSet(iterator) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
vkedia
commented
Jul 20, 2017
The documentation on this page suggests that snapshot already allows you to do multiple reads at a consistent snapshot. In light of this PR that is clearly incorrect. @jonparrott We also claim the same thing in our [sample code]) @lukesneeringer@bjwatson Can we please get this merged asap. This is a severe bug. |
lukesneeringer
left a comment
There was a problem hiding this comment.
Seeing no actual concerns (either in my own review or the other comments), this is good to go out.
vkedia
commented
Jul 20, 2017
@lukesneeringer I believe my comments need to be addressed before merging this. Specifically |
vkedia
commented
Jul 21, 2017
@tseaver Any updates on this? |
tseaver
commented
Jul 24, 2017
I can see adding an explicit In addition, I had thought of having a |
- Convert 'Database.snapshot' and 'Session.snapshot' factories to take / forward '**kw'.
- When reading / executing SQL for a multi-use snapshot, pass the snapshot as the iterator's source.
- PartialResultSet - ResultSetMetadata - ResultSetStats.
- Source will only be set for multi-use snapshots.
799ce25 to
230d715CompareTo implement the single-use request guard, the snapshot needs to maintain a request counter, which we can use to detect the "interleaved" case. |
vkedia
commented
Jul 24, 2017
That sounds good. We can have an explicit |
vkedia
commented
Jul 24, 2017
Actually why do we need |
|
1fff028 to
5dc09f8Comparetseaver
commented
Jul 24, 2017
@vkedia I've just updated the system tests to pass ________________TestSessionAPI.test_execute_sql_w_query_param_________________Traceback (mostrecentcalllast):
File"/home/tseaver/projects/agendaless/Google/src/google-cloud-python/spanner/tests/system/test_system.py", line960, intest_execute_sql_w_query_paramexpected=[(19,), (99,)],
File"/home/tseaver/projects/agendaless/Google/src/google-cloud-python/spanner/tests/system/test_system.py", line888, in_check_sql_resultssql, params=params, param_types=param_types))
File"/home/tseaver/projects/agendaless/Google/src/google-cloud-python/spanner/.nox/sys-3-6/lib/python3.6/site-packages/google/cloud/spanner/streamed.py", line166, in__iter__self.consume_next() # raises StopIterationFile"/home/tseaver/projects/agendaless/Google/src/google-cloud-python/spanner/.nox/sys-3-6/lib/python3.6/site-packages/google/cloud/spanner/streamed.py", line132, inconsume_nextresponse=six.next(self._response_iterator)
File"/home/tseaver/projects/agendaless/Google/src/google-cloud-python/spanner/.nox/sys-3-6/lib/python3.6/site-packages/grpc/_channel.py", line363, in__next__returnself._next()
File"/home/tseaver/projects/agendaless/Google/src/google-cloud-python/spanner/.nox/sys-3-6/lib/python3.6/site-packages/grpc/_channel.py", line357, in_nextraiseselfgrpc._channel._Rendezvous: <_RendezvousofRPCthatterminatedwith (StatusCode.INVALID_ARGUMENT, Transactionwasstartedinadifferentsession.)>______________________TestSessionAPI.test_read_w_ranges_______________________Traceback (mostrecentcalllast):
File"/home/tseaver/projects/agendaless/Google/src/google-cloud-python/spanner/tests/system/test_system.py", line846, intest_read_w_rangesself.TABLE, self.COLUMNS, keyset))
File"/home/tseaver/projects/agendaless/Google/src/google-cloud-python/spanner/.nox/sys-3-6/lib/python3.6/site-packages/google/cloud/spanner/streamed.py", line166, in__iter__self.consume_next() # raises StopIterationFile"/home/tseaver/projects/agendaless/Google/src/google-cloud-python/spanner/.nox/sys-3-6/lib/python3.6/site-packages/google/cloud/spanner/streamed.py", line132, inconsume_nextresponse=six.next(self._response_iterator)
File"/home/tseaver/projects/agendaless/Google/src/google-cloud-python/spanner/.nox/sys-3-6/lib/python3.6/site-packages/grpc/_channel.py", line363, in__next__returnself._next()
File"/home/tseaver/projects/agendaless/Google/src/google-cloud-python/spanner/.nox/sys-3-6/lib/python3.6/site-packages/grpc/_channel.py", line357, in_nextraiseselfgrpc._channel._Rendezvous: <_RendezvousofRPCthatterminatedwith (StatusCode.INVALID_ARGUMENT, Transactionwasstartedinadifferentsession.)>I tried putting an explicit |
tseaver
commented
Jul 24, 2017
Looks like the back-end passes back an empty transaction ID for read requests after the first one. 0966806 keeps us from clearing it in that case. |
vkedia
commented
Jul 24, 2017
Thats right. Transaction field is only set if the read or query started a new transaction. |
tseaver
commented
Jul 24, 2017
The new system tests are passing. |
dhermes
commented
Jul 24, 2017
@tseaver What are you looking for here in terms of review? |
tseaver
commented
Jul 24, 2017
@dhermes the commits which are new since @lukesneeringer gave an LGTM on Thursday (the rest are just rebase to fix conflicts). a5219a5 is the hash of that rebased commit, so the diff would be: a5219a5...spanner-multi_use_snapshot |
tseaver
commented
Jul 26, 2017
dhermes
commented
Jul 26, 2017
LGTM |
bjwatson
commented
Jul 26, 2017
@tseaver I just saw this. I think that @vkedia will want to review this more when he returns from vacation on Monday. I guess if he finds anything else, it can be addressed in a separate PR. Let's remain Alpha until next week. (FYI @lukesneeringer) |
bjwatson
commented
Aug 8, 2017
@vkedia Do you plan to finish reviewing this post-merge? |
Multi-use snapshots trigger an "implicit" server-side transaction, and capture its ID on the first request. Subsequent requests return that ID, allowing for isolation from other changes. We default to
multi_use=Falsebecause that mode is much more performant for the simple case.This feature is one which we originally decided to leave out, but the P0 system test list requires that it be implemented.
I think that a commitwise review might be easier than reviewing the whole enchilada.