Uploaded image for project: 'Python Driver'
  1. Python Driver
  2. PYTHON-1936

Remove listCollections check from Database.create_collection

    • Type: Icon: Improvement Improvement
    • Resolution: Won't Do
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • Component/s: None
    • None

      Database.create_collection runs the listCollections command to check if the collection already exists on the server and if so raises CollectionInvalid:

      >>> client.admin.create_collection('test')
      Collection(Database(MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True), 'admin'), 'test')
      >>> client.admin.create_collection('test')
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pymongo/database.py", line 365, in create_collection
          raise CollectionInvalid("collection %s already exists" % name)
      pymongo.errors.CollectionInvalid: collection test already exists
      

      But the server already returns an error if the collection already exists (since at least MongoDB 2.6):

      >>> client.server_info()['version']
      '2.6.12'
      >>> client.admin.command('create', 'test')
      {'ok': 1.0}
      >>> client.admin.command('create', 'test')
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pymongo/database.py", line 614, in command
          codec_options, session=session, **kwargs)
        File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pymongo/database.py", line 514, in _command
          client=self.__client)
        File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pymongo/pool.py", line 579, in command
          unacknowledged=unacknowledged)
        File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pymongo/network.py", line 150, in command
          parse_write_concern_error=parse_write_concern_error)
        File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pymongo/helpers.py", line 155, in _check_command_response
          raise OperationFailure(msg % errmsg, code, response)
      pymongo.errors.OperationFailure: collection already exists
      

      Additionally this client side check introduces a time-of-check to time-of-use race condition where:

      1. Thread A runs db.create_collection('test')
      2. Thread A runs listCollections and sees that the collection does not exist
      3. Meanwhile, Thread B runs db.create_collection('test') to completion
      4. db.test now exists on the server
      5. Thread A resumes and runs the create command which fails with OperationFailure: collection already exists

      Instead we should just rely on the server to decide.

      We can even make this change backwards compatible by catching the OperationFailure: collection already exists error and raising CollectionInvalid: collection test already exists instead.

            Assignee:
            julius.park@mongodb.com Julius Park (Inactive)
            Reporter:
            shane.harvey@mongodb.com Shane Harvey
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: