Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 1.8k
Making datastore batch/transaction more robust to failure.#2303
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -90,6 +90,8 @@ class Transaction(Batch): | ||
| :param client: the client used to connect to datastore. | ||
| """ | ||
| _status = None | ||
This comment was marked as spam.Sorry, something went wrong. Uh oh!There was an error while loading. Please reload this page. | ||
| def __init__(self, client): | ||
| super(Transaction, self).__init__(client) | ||
| self._id = None | ||
| @@ -125,10 +127,15 @@ def begin(self): | ||
| statement, however it can be called explicitly if you don't want | ||
| to use a context manager. | ||
| :raises: :class:`ValueError` if the transaction has already begun. | ||
| :raises: :class:`~exceptions.ValueError` if the transaction has | ||
| already begun. | ||
| """ | ||
| super(Transaction, self).begin() | ||
| self._id = self.connection.begin_transaction(self.project) | ||
| try: | ||
| self._id = self.connection.begin_transaction(self.project) | ||
| except: | ||
| self._status = self._ABORTED | ||
| raise | ||
| def rollback(self): | ||
| """Rolls back the current transaction. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -68,8 +68,20 @@ def test_put_entity_wo_key(self): | ||
| client = _Client(_PROJECT, connection) | ||
| batch = self._makeOne(client) | ||
| batch.begin() | ||
| self.assertRaises(ValueError, batch.put, _Entity()) | ||
| def test_put_entity_wrong_status(self): | ||
| _PROJECT = 'PROJECT' | ||
| connection = _Connection() | ||
| client = _Client(_PROJECT, connection) | ||
| batch = self._makeOne(client) | ||
| entity = _Entity() | ||
| entity.key = _Key('OTHER') | ||
| self.assertEqual(batch._status, batch._INITIAL) | ||
| self.assertRaises(ValueError, batch.put, entity) | ||
| def test_put_entity_w_key_wrong_project(self): | ||
| _PROJECT = 'PROJECT' | ||
| connection = _Connection() | ||
| @@ -78,6 +90,7 @@ def test_put_entity_w_key_wrong_project(self): | ||
| entity = _Entity() | ||
| entity.key = _Key('OTHER') | ||
| batch.begin() | ||
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.Sorry, something went wrong. Uh oh!There was an error while loading. Please reload this page. | ||
| self.assertRaises(ValueError, batch.put, entity) | ||
| def test_put_entity_w_partial_key(self): | ||
| @@ -90,6 +103,7 @@ def test_put_entity_w_partial_key(self): | ||
| key = entity.key = _Key(_PROJECT) | ||
| key._id = None | ||
| batch.begin() | ||
| batch.put(entity) | ||
| mutated_entity = _mutated_pb(self, batch.mutations, 'insert') | ||
| @@ -113,6 +127,7 @@ def test_put_entity_w_completed_key(self): | ||
| entity.exclude_from_indexes = ('baz', 'spam') | ||
| key = entity.key = _Key(_PROJECT) | ||
| batch.begin() | ||
| batch.put(entity) | ||
| mutated_entity = _mutated_pb(self, batch.mutations, 'upsert') | ||
| @@ -129,6 +144,17 @@ def test_put_entity_w_completed_key(self): | ||
| self.assertTrue(spam_values[2].exclude_from_indexes) | ||
| self.assertFalse('frotz' in prop_dict) | ||
| def test_delete_wrong_status(self): | ||
| _PROJECT = 'PROJECT' | ||
| connection = _Connection() | ||
| client = _Client(_PROJECT, connection) | ||
| batch = self._makeOne(client) | ||
| key = _Key(_PROJECT) | ||
| key._id = None | ||
| self.assertEqual(batch._status, batch._INITIAL) | ||
| self.assertRaises(ValueError, batch.delete, key) | ||
| def test_delete_w_partial_key(self): | ||
| _PROJECT = 'PROJECT' | ||
| connection = _Connection() | ||
| @@ -137,6 +163,7 @@ def test_delete_w_partial_key(self): | ||
| key = _Key(_PROJECT) | ||
| key._id = None | ||
| batch.begin() | ||
| self.assertRaises(ValueError, batch.delete, key) | ||
| def test_delete_w_key_wrong_project(self): | ||
| @@ -146,6 +173,7 @@ def test_delete_w_key_wrong_project(self): | ||
| batch = self._makeOne(client) | ||
| key = _Key('OTHER') | ||
| batch.begin() | ||
| self.assertRaises(ValueError, batch.delete, key) | ||
| def test_delete_w_completed_key(self): | ||
| @@ -155,6 +183,7 @@ def test_delete_w_completed_key(self): | ||
| batch = self._makeOne(client) | ||
| key = _Key(_PROJECT) | ||
| batch.begin() | ||
| batch.delete(key) | ||
| mutated_key = _mutated_pb(self, batch.mutations, 'delete') | ||
| @@ -180,23 +209,43 @@ def test_rollback(self): | ||
| _PROJECT = 'PROJECT' | ||
| client = _Client(_PROJECT, None) | ||
| batch = self._makeOne(client) | ||
| self.assertEqual(batch._status, batch._INITIAL) | ||
| batch.begin() | ||
| self.assertEqual(batch._status, batch._IN_PROGRESS) | ||
| batch.rollback() | ||
| self.assertEqual(batch._status, batch._ABORTED) | ||
| def test_rollback_wrong_status(self): | ||
| _PROJECT = 'PROJECT' | ||
| client = _Client(_PROJECT, None) | ||
| batch = self._makeOne(client) | ||
| self.assertEqual(batch._status, batch._INITIAL) | ||
| self.assertRaises(ValueError, batch.rollback) | ||
| def test_commit(self): | ||
| _PROJECT = 'PROJECT' | ||
| connection = _Connection() | ||
| client = _Client(_PROJECT, connection) | ||
| batch = self._makeOne(client) | ||
| self.assertEqual(batch._status, batch._INITIAL) | ||
| batch.begin() | ||
| self.assertEqual(batch._status, batch._IN_PROGRESS) | ||
| batch.commit() | ||
| self.assertEqual(batch._status, batch._FINISHED) | ||
| self.assertEqual(connection._committed, | ||
| [(_PROJECT, batch._commit_request, None)]) | ||
| def test_commit_wrong_status(self): | ||
| _PROJECT = 'PROJECT' | ||
| connection = _Connection() | ||
| client = _Client(_PROJECT, connection) | ||
| batch = self._makeOne(client) | ||
| self.assertEqual(batch._status, batch._INITIAL) | ||
| self.assertRaises(ValueError, batch.commit) | ||
| def test_commit_w_partial_key_entities(self): | ||
| _PROJECT = 'PROJECT' | ||
| _NEW_ID = 1234 | ||
| @@ -209,6 +258,8 @@ def test_commit_w_partial_key_entities(self): | ||
| batch._partial_key_entities.append(entity) | ||
| self.assertEqual(batch._status, batch._INITIAL) | ||
| batch.begin() | ||
| self.assertEqual(batch._status, batch._IN_PROGRESS) | ||
| batch.commit() | ||
| self.assertEqual(batch._status, batch._FINISHED) | ||
| @@ -295,6 +346,26 @@ def test_as_context_mgr_w_error(self): | ||
| self.assertEqual(mutated_entity.key, key._key) | ||
| self.assertEqual(connection._committed, []) | ||
| def test_as_context_mgr_enter_fails(self): | ||
| klass = self._getTargetClass() | ||
| class FailedBegin(klass): | ||
| def begin(self): | ||
| raise RuntimeError | ||
| client = _Client(None, None) | ||
| self.assertEqual(client._batches, []) | ||
| batch = FailedBegin(client) | ||
| with self.assertRaises(RuntimeError): | ||
| # The context manager will never be entered because | ||
| # of the failure. | ||
| with batch: # pragma: NO COVER | ||
| pass | ||
| # Make sure no batch was added. | ||
| self.assertEqual(client._batches, []) | ||
| class _PathElementPB(object): | ||
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.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.