Skip to content

Transactions are commited in CommitRequest.NON_TRANSACTIONAL mode #903

Description

@mwitkow

We have just been bitten by this using the latest 0.5.0.

We had the following piece of code, run in two different threads:

with dataset.transaction as t:
  entity = dataset.get(entity_key)
  archived_entity = _move_to_archive_key(entity)
  t.delete(entity.key)
  t.put(archived_entity)
  return archived_entity

We've seen two copies of the archived_entity for the same entity. We've managed to reproduce it with two threads performing this concurrently (running separate Connections each, because httplib2 is not thread safe).

Having used Datastore's underlying technology before, I expected to get a ConcurrentModificationException on delete, and one of the threads throwing it, similar to what the Java API for AppEngine describes:
https://cloud.google.com/appengine/docs/java/datastore/transactions#Java_Uses_for_transactions

However, both of them succeed creating two copies of archived_entity, and there's no ConcurrentModificationException anywhere in gcloud-python code.

We've tracked down to the following:

Impact: This means that all transactions made through python-gcloud are non-transactional. Please treat it as a P0 bug.

Activity

  1. mwitkow commented on Jun 1, 2015

    @mwitkow
    Author

    We managed to get the correct behaviour by plumbing through Transaction#id through Batch#commit. The result is that the above test code works as intended: one thread doest the complete transaction, the other one gets:

     File "~/src/python/improbable/db/common/transaction.py", line 15, in commit
       response = self.connection.commit(self._dataset_id, self.mutation, self._id)
     File "~/virtualenv/python/local/lib/python2.7/site-packages/gcloud/datastore/connection.py", line 324, in commit
       datastore_pb.CommitResponse)
     File "~/virtualenv/python/local/lib/python2.7/site-packages/gcloud/datastore/connection.py", line 108, in _rpc
       data=request_pb.SerializeToString())
     File "~/virtualenv/python/local/lib/python2.7/site-packages/gcloud/datastore/connection.py", line 85, in _request
       raise make_exception(headers, content, use_json=False)
    Conflict: 409 too much contention on these datastore entities. please try again.

    I think the right solution here would be to catch it in the Transaction#commit and rethrow it as ConcurrentModificationException.

  2. self-assigned this
    on Jun 1, 2015
  3. added a commit that references this issue on Jun 1, 2015
  4. mwitkow commented on Jun 1, 2015

    @mwitkow
    Author

    What's the ETA on a version that supports it? :)

    Also, this currently has a very clunky API, since there is no ConcurrentModificationException. This means that the opportunistic concurrency model of Datastore is poorly exposed to the end user.

  5. dhermes commented on Jun 4, 2015

    @dhermes
    Contributor

    @mwitkow-io I'm going to cut a release today (or tomorrow).

  6. dhermes commented on Jun 4, 2015

    @dhermes
    Contributor

    RE: "opportunistic concurrency model of Datastore is poorly exposed to the end user." we expect the error status codes and error messages from the Datastore API (the RPC service) to be useful. If there are issues where they aren't useful, we should take it up with the API folks.

    The ConcurrentModificationException in App Engine corresponds to one of these RPC statuses.

  7. dhermes commented on Jun 4, 2015

    @dhermes
    Contributor

    @mwitkow-io Also I'd love to chat about lack of thread-safety in httplib2 and how you address it. Want to hop on a video chat?

    We actually don't require use of it, but this is not at all clear from our docs (and may never be).

  8. dhermes commented on Jun 4, 2015

    @dhermes
    Contributor

    @mwitkow-io Also I'd love to chat about lack of thread-safety in httplib2 and how you address it. Want to hop on a video chat?

    We actually don't require use of it, but this is not at all clear from our docs (and may never be).

  9. mwitkow commented on Jun 4, 2015

    @mwitkow
    Author

    Sure thing, would be great to chat!

    I'm in London though, so 8h diff to MTV. 5pm tomorrow BST? Please send a
    call invite :-)

    On Thu, 4 Jun 2015 18:47 Danny Hermes notifications@github.com wrote:

    @mwitkow-io https://github.com/mwitkow-io Also I'd love to chat about
    lack of thread-safety in httplib2 and how you address it. Want to hop on
    a video chat?

    We actually don't require use of it, but this is not at all clear from our
    docs (and may never be).

    —
    Reply to this email directly or view it on GitHub
    #903 (comment)
    .

  10. dhermes commented on Jun 4, 2015

    @dhermes
    Contributor

    Invite sent for 4pm your time (if you're free). I assumed you use the email listed on your GitHub profile. If 4pm doesn't work I gave you edit privileges on the event.

  11. mwitkow commented on Jun 4, 2015

    @mwitkow
    Author

    Thanks, that works great :-)

    On Thu, 4 Jun 2015 19:16 Danny Hermes notifications@github.com wrote:

    Invite sent for 4pm your time (if you're free). I assumed you use the
    email listed on your GitHub profile. If 4pm doesn't work I gave you edit
    privileges on the event.

    —
    Reply to this email directly or view it on GitHub
    #903 (comment)
    .

  12. added
    type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.
    api: datastoreIssues related to the Datastore API.
    on Dec 31, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

api: datastoreIssues related to the Datastore API.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions