# Copyright 2009-2012 10gen, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Tools for creating `messages `_ to be sent to MongoDB. .. note:: This module is for internal use and is generally not needed by application developers. .. versionadded:: 1.1.2 """ import random import struct import asyncio_mongo._bson as bson from asyncio_mongo._bson.binary import OLD_UUID_SUBTYPE from asyncio_mongo._bson.py3compat import b from asyncio_mongo._bson.son import SON try: from asyncio_mongo._pymongo import _cmessage _use_c = True except ImportError: _use_c = False from asyncio_mongo._pymongo.errors import InvalidDocument, InvalidOperation, OperationFailure __ZERO = b("\x00\x00\x00\x00") EMPTY = b("") MAX_INT32 = 2147483647 MIN_INT32 = -2147483648 def __last_error(namespace, args): """Data to send to do a lastError. """ cmd = SON([("getlasterror", 1)]) cmd.update(args) splitns = namespace.split('.', 1) return query(0, splitns[0] + '.$cmd', 0, -1, cmd) def __pack_message(operation, data): """Takes message data and adds a message header based on the operation. Returns the resultant message string. """ request_id = random.randint(MIN_INT32, MAX_INT32) message = struct.pack(" client.max_bson_size: raise InvalidDocument("BSON document too large (%d bytes)" " - the connected server supports" " BSON document sizes up to %d" " bytes." % (encoded_length, client.max_bson_size)) message_length += encoded_length if message_length < client.max_message_size: data.append(encoded) continue # We have enough data, send this message. send_safe = safe or not continue_on_error try: client._send_message(_insert_message(EMPTY.join(data), send_safe), send_safe) # Exception type could be OperationFailure or a subtype # (e.g. DuplicateKeyError) except OperationFailure as exc: # Like it says, continue on error... if continue_on_error: # Store exception details to re-raise after the final batch. last_error = exc # With unacknowledged writes just return at the first error. elif not safe: return # With acknowledged writes raise immediately. else: raise message_length = len(begin) + encoded_length data = [begin, encoded] client._send_message(_insert_message(EMPTY.join(data), safe), safe) # Re-raise any exception stored due to continue_on_error if last_error is not None: raise last_error if _use_c: _do_batched_insert = _cmessage._do_batched_insert