Skip to content

Conversation

@appcove
Copy link

@appcove appcove commented Feb 5, 2012

Hello,

I was attempting to get Mongo 1.8 working with Python 3.1.4. Upon making any connection to the server, I was greeted with this stack trace:

>>> x = pymongo.Connection('localhost', 27017)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pymongo/connection.py", line 170, in __init__
    self.__find_master()
  File "pymongo/connection.py", line 342, in __find_master
    master = self.__master(sock)
  File "pymongo/connection.py", line 227, in __master
    result = self["admin"].command({"ismaster": 1}, _sock=sock)
  File "pymongo/database.py", line 215, in command
    _is_command=True)
  File "pymongo/collection.py", line 347, in find_one
    _is_command=_is_command):
  File "pymongo/cursor.py", line 482, in __next__
    if len(self.__data) or self._refresh():
  File "pymongo/cursor.py", line 458, in _refresh
    self.__query_spec(), self.__fields))
  File "pymongo/cursor.py", line 426, in __send_message
    response = helpers._unpack_response(response, self.__id)
  File "pymongo/helpers.py", line 98, in _unpack_response
    assert response_flag == 0
AssertionError

The problem was caused by response_flag bit mongodb#3 being set as of Mongo 1.6. This tripped the AssertionError.

In pymongo.helpers._unpack_response, there was a problem in how the
responseFlags were being parsed. Rather than checking to see if each
bit was set with a bitwise AND, the == operator was being used. This
meant that if more than one flag was ever set, then the == would return
False, and the logic would proceed incorrectly.

This has been changed to response_flag & 2 to check for bit #1.
The value 2 is derived from boolean 0b0010, meaning bit #1.

The actual problem appears to have been introduced in Mongod 1.6 when
bit mongodb#3 is always set:

AwaitCapable:  Set when the server supports the AwaitData Query
option. If it doesn't, a client should sleep a little between
getMore's of a Tailable cursor. Mongod version 1.6 supports AwaitData
and thus always sets AwaitCapable.

Thanks!
Jason Garber

@appcove
Copy link
Author

appcove commented Feb 5, 2012

It may make more sense to just incorporate the code from the official mongo python driver:

    response_flag = struct.unpack("<i", response[:4])[0]
    if response_flag & 1:
        # Shouldn't get this response if we aren't doing a getMore
        assert cursor_id is not None

        raise OperationFailure("cursor id '%s' not valid at server" %
                               cursor_id)
    elif response_flag & 2:
        error_object = bson.BSON(response[20:]).decode()
        if error_object["$err"].startswith("not master"):
            raise AutoReconnect("master has changed")
        raise OperationFailure("database error: %s" %
                               error_object["$err"])

…truct

In pymongo.helpers._unpack_response, there was a problem in how the
responseFlags were being parsed.  Rather than checking to see if each
bit was set with a bitwise AND, the == operator was being used.  This
meant that if more than one flag was ever set, then the == would return
False, and the logic would proceed incorrectly.

This has been changed to `response_flag & 2` to check for bit #1.
The value `2` is derived from boolean 0b0010, meaning bit #1.

The actual problem appears to have been introduced in Mongod 1.6 when
bit mongodb#3 is always set:

    AwaitCapable:  Set when the server supports the AwaitData Query
    option. If it doesn't, a client should sleep a little between
    getMore's of a Tailable cursor. Mongod version 1.6 supports AwaitData
    and thus always sets AwaitCapable.
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant