00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 """Tools for connecting to MongoDB.
00016
00017 .. seealso:: Module :mod:`~pymongo.master_slave_connection` for
00018 connecting to master-slave clusters, and
00019 :doc:`/examples/replica_set` for an example of how to connect to a
00020 replica set.
00021
00022 To get a :class:`~pymongo.database.Database` instance from a
00023 :class:`Connection` use either dictionary-style or attribute-style
00024 access:
00025
00026 .. doctest::
00027
00028 >>> from pymongo import Connection
00029 >>> c = Connection()
00030 >>> c.test_database
00031 Database(Connection('localhost', 27017), u'test_database')
00032 >>> c['test-database']
00033 Database(Connection('localhost', 27017), u'test-database')
00034 """
00035
00036 import datetime
00037 import os
00038 import select
00039 import socket
00040 import struct
00041 import threading
00042 import time
00043 import warnings
00044
00045 from pymongo import (database,
00046 helpers,
00047 message)
00048 from pymongo.cursor_manager import CursorManager
00049 from pymongo.errors import (AutoReconnect,
00050 ConfigurationError,
00051 ConnectionFailure,
00052 DuplicateKeyError,
00053 InvalidDocument,
00054 InvalidURI,
00055 OperationFailure)
00056
00057
00058 _CONNECT_TIMEOUT = 20.0
00059
00060
00061 def _partition(source, sub):
00062 """Our own string partitioning method.
00063
00064 Splits `source` on `sub`.
00065 """
00066 i = source.find(sub)
00067 if i == -1:
00068 return (source, None)
00069 return (source[:i], source[i + len(sub):])
00070
00071
00072 def _str_to_node(string, default_port=27017):
00073 """Convert a string to a node tuple.
00074
00075 "localhost:27017" -> ("localhost", 27017)
00076 """
00077 (host, port) = _partition(string, ":")
00078 if port:
00079 port = int(port)
00080 else:
00081 port = default_port
00082 return (host, port)
00083
00084
00085 def _parse_uri(uri, default_port=27017):
00086 """MongoDB URI parser.
00087 """
00088
00089 if uri.startswith("mongodb://"):
00090 uri = uri[len("mongodb://"):]
00091 elif "://" in uri:
00092 raise InvalidURI("Invalid uri scheme: %s" % _partition(uri, "://")[0])
00093
00094 (hosts, namespace) = _partition(uri, "/")
00095
00096 raw_options = None
00097 if namespace:
00098 (namespace, raw_options) = _partition(namespace, "?")
00099 if namespace.find(".") < 0:
00100 db = namespace
00101 collection = None
00102 else:
00103 (db, collection) = namespace.split(".", 1)
00104 else:
00105 db = None
00106 collection = None
00107
00108 username = None
00109 password = None
00110 if "@" in hosts:
00111 (auth, hosts) = _partition(hosts, "@")
00112
00113 if ":" not in auth:
00114 raise InvalidURI("auth must be specified as "
00115 "'username:password@'")
00116 (username, password) = _partition(auth, ":")
00117
00118 host_list = []
00119 for host in hosts.split(","):
00120 if not host:
00121 raise InvalidURI("empty host (or extra comma in host list)")
00122 host_list.append(_str_to_node(host, default_port))
00123
00124 options = {}
00125 if raw_options:
00126 and_idx = raw_options.find("&")
00127 semi_idx = raw_options.find(";")
00128 if and_idx >= 0 and semi_idx >= 0:
00129 raise InvalidURI("Cannot mix & and ; for option separators.")
00130 elif and_idx >= 0:
00131 options = dict([kv.split("=") for kv in raw_options.split("&")])
00132 elif semi_idx >= 0:
00133 options = dict([kv.split("=") for kv in raw_options.split(";")])
00134 elif raw_options.find("="):
00135 options = dict([raw_options.split("=")])
00136
00137
00138 return (host_list, db, username, password, collection, options)
00139
00140
00141 def _closed(sock):
00142 """Return True if we know socket has been closed, False otherwise.
00143 """
00144 rd, _, _ = select.select([sock], [], [], 0)
00145 try:
00146 return len(rd) and sock.recv() == ""
00147 except:
00148 return True
00149
00150
00151 class _Pool(threading.local):
00152 """A simple connection pool.
00153
00154 Uses thread-local socket per thread. By calling return_socket() a
00155 thread can return a socket to the pool. Right now the pool size is
00156 capped at 10 sockets - we can expose this as a parameter later, if
00157 needed.
00158 """
00159
00160
00161 __slots__ = ["sockets", "socket_factory", "pool_size", "pid"]
00162
00163
00164 sock = None
00165
00166 def __init__(self, socket_factory):
00167 self.pid = os.getpid()
00168 self.pool_size = 10
00169 self.socket_factory = socket_factory
00170 if not hasattr(self, "sockets"):
00171 self.sockets = []
00172
00173
00174 def socket(self):
00175
00176
00177
00178 pid = os.getpid()
00179
00180 if pid != self.pid:
00181 self.sock = None
00182 self.sockets = []
00183 self.pid = pid
00184
00185 if self.sock is not None and self.sock[0] == pid:
00186 return self.sock[1]
00187
00188 try:
00189 self.sock = (pid, self.sockets.pop())
00190 except IndexError:
00191 self.sock = (pid, self.socket_factory())
00192
00193 return self.sock[1]
00194
00195 def return_socket(self):
00196 if self.sock is not None and self.sock[0] == os.getpid():
00197
00198
00199
00200 if len(self.sockets) < self.pool_size:
00201 self.sockets.append(self.sock[1])
00202 else:
00203 self.sock[1].close()
00204 self.sock = None
00205
00206
00207 class Connection(object):
00208 """Connection to MongoDB.
00209 """
00210
00211 HOST = "localhost"
00212 PORT = 27017
00213
00214 __max_bson_size = 4 * 1024 * 1024
00215
00216 def __init__(self, host=None, port=None, pool_size=None,
00217 auto_start_request=None, timeout=None, slave_okay=False,
00218 network_timeout=None, document_class=dict, tz_aware=False,
00219 _connect=True):
00220 """Create a new connection to a single MongoDB instance at *host:port*.
00221
00222 The resultant connection object has connection-pooling built
00223 in. It also performs auto-reconnection when necessary. If an
00224 operation fails because of a connection error,
00225 :class:`~pymongo.errors.ConnectionFailure` is raised. If
00226 auto-reconnection will be performed,
00227 :class:`~pymongo.errors.AutoReconnect` will be
00228 raised. Application code should handle this exception
00229 (recognizing that the operation failed) and then continue to
00230 execute.
00231
00232 Raises :class:`TypeError` if port is not an instance of
00233 ``int``. Raises :class:`~pymongo.errors.ConnectionFailure` if
00234 the connection cannot be made.
00235
00236 The `host` parameter can be a full `mongodb URI
00237 <http://dochub.mongodb.org/core/connections>`_, in addition to
00238 a simple hostname. It can also be a list of hostnames or
00239 URIs. Any port specified in the host string(s) will override
00240 the `port` parameter. If multiple mongodb URIs containing
00241 database or auth information are passed, the last database,
00242 username, and password present will be used.
00243
00244 :Parameters:
00245 - `host` (optional): hostname or IPv4 address of the
00246 instance to connect to, or a mongodb URI, or a list of
00247 hostnames / mongodb URIs
00248 - `port` (optional): port number on which to connect
00249 - `pool_size` (optional): DEPRECATED
00250 - `auto_start_request` (optional): DEPRECATED
00251 - `slave_okay` (optional): is it okay to connect directly to
00252 and perform queries on a slave instance
00253 - `timeout` (optional): DEPRECATED
00254 - `network_timeout` (optional): timeout (in seconds) to use
00255 for socket operations - default is no timeout
00256 - `document_class` (optional): default class to use for
00257 documents returned from queries on this connection
00258 - `tz_aware` (optional): if ``True``,
00259 :class:`~datetime.datetime` instances returned as values
00260 in a document by this :class:`Connection` will be timezone
00261 aware (otherwise they will be naive)
00262
00263 .. seealso:: :meth:`end_request`
00264 .. versionchanged:: 1.8
00265 The `host` parameter can now be a full `mongodb URI
00266 <http://dochub.mongodb.org/core/connections>`_, in addition
00267 to a simple hostname. It can also be a list of hostnames or
00268 URIs.
00269 .. versionadded:: 1.8
00270 The `tz_aware` parameter.
00271 .. versionadded:: 1.7
00272 The `document_class` parameter.
00273 .. versionchanged:: 1.4
00274 DEPRECATED The `pool_size`, `auto_start_request`, and `timeout`
00275 parameters.
00276 .. versionadded:: 1.1
00277 The `network_timeout` parameter.
00278
00279 .. mongodoc:: connections
00280 """
00281 if host is None:
00282 host = self.HOST
00283 if isinstance(host, basestring):
00284 host = [host]
00285 if port is None:
00286 port = self.PORT
00287 if not isinstance(port, int):
00288 raise TypeError("port must be an instance of int")
00289
00290 nodes = set()
00291 database = None
00292 username = None
00293 password = None
00294 collection = None
00295 options = {}
00296 for uri in host:
00297 (n, db, u, p, coll, opts) = _parse_uri(uri, port)
00298 nodes.update(n)
00299 database = db or database
00300 username = u or username
00301 password = p or password
00302 collection = coll or collection
00303 options = opts or options
00304 if not nodes:
00305 raise ConfigurationError("need to specify at least one host")
00306 self.__nodes = nodes
00307 if database and username is None:
00308 raise InvalidURI("cannot specify database without "
00309 "a username and password")
00310
00311 if pool_size is not None:
00312 warnings.warn("The pool_size parameter to Connection is "
00313 "deprecated", DeprecationWarning)
00314 if auto_start_request is not None:
00315 warnings.warn("The auto_start_request parameter to Connection "
00316 "is deprecated", DeprecationWarning)
00317 if timeout is not None:
00318 warnings.warn("The timeout parameter to Connection is deprecated",
00319 DeprecationWarning)
00320
00321 self.__host = None
00322 self.__port = None
00323
00324 for k in options.iterkeys():
00325
00326 if k in ("slaveOk", "slaveok"):
00327 self.__slave_okay = (options[k][0].upper() == 'T')
00328 break
00329 else:
00330 self.__slave_okay = slave_okay
00331
00332 if slave_okay and len(self.__nodes) > 1:
00333 raise ConfigurationError("cannot specify slave_okay for a paired "
00334 "or replica set connection")
00335
00336
00337 self.__options = options
00338
00339 self.__collection = collection
00340
00341 self.__cursor_manager = CursorManager(self)
00342
00343 self.__pool = _Pool(self.__connect)
00344 self.__last_checkout = time.time()
00345
00346 self.__network_timeout = network_timeout
00347 self.__document_class = document_class
00348 self.__tz_aware = tz_aware
00349
00350
00351 self.__index_cache = {}
00352
00353 if _connect:
00354 self.__find_master()
00355
00356 if username:
00357 database = database or "admin"
00358 if not self[database].authenticate(username, password):
00359 raise ConfigurationError("authentication failed")
00360
00361 @classmethod
00362 def from_uri(cls, uri="mongodb://localhost", **connection_args):
00363 """DEPRECATED Can pass a mongodb URI directly to Connection() instead.
00364
00365 .. versionchanged:: 1.8
00366 DEPRECATED
00367 .. versionadded:: 1.5
00368 """
00369 warnings.warn("Connection.from_uri is deprecated - can pass "
00370 "URIs to Connection() now", DeprecationWarning)
00371 return cls(uri, **connection_args)
00372
00373 @classmethod
00374 def paired(cls, left, right=None, **connection_args):
00375 """DEPRECATED Can pass a list of hostnames to Connection() instead.
00376
00377 .. versionchanged:: 1.8
00378 DEPRECATED
00379 """
00380 warnings.warn("Connection.paired is deprecated - can pass multiple "
00381 "hostnames to Connection() now", DeprecationWarning)
00382 if isinstance(left, str) or isinstance(right, str):
00383 raise TypeError("arguments to paired must be tuples")
00384 if right is None:
00385 right = (cls.HOST, cls.PORT)
00386 return cls([":".join(map(str, left)), ":".join(map(str, right))],
00387 **connection_args)
00388
00389 def _cache_index(self, database, collection, index, ttl):
00390 """Add an index to the index cache for ensure_index operations.
00391
00392 Return ``True`` if the index has been newly cached or if the index had
00393 expired and is being re-cached.
00394
00395 Return ``False`` if the index exists and is valid.
00396 """
00397 now = datetime.datetime.utcnow()
00398 expire = datetime.timedelta(seconds=ttl) + now
00399
00400 if database not in self.__index_cache:
00401 self.__index_cache[database] = {}
00402 self.__index_cache[database][collection] = {}
00403 self.__index_cache[database][collection][index] = expire
00404 return True
00405
00406 if collection not in self.__index_cache[database]:
00407 self.__index_cache[database][collection] = {}
00408 self.__index_cache[database][collection][index] = expire
00409 return True
00410
00411 if index in self.__index_cache[database][collection]:
00412 if now < self.__index_cache[database][collection][index]:
00413 return False
00414
00415 self.__index_cache[database][collection][index] = expire
00416 return True
00417
00418 def _purge_index(self, database_name,
00419 collection_name=None, index_name=None):
00420 """Purge an index from the index cache.
00421
00422 If `index_name` is None purge an entire collection.
00423
00424 If `collection_name` is None purge an entire database.
00425 """
00426 if not database_name in self.__index_cache:
00427 return
00428
00429 if collection_name is None:
00430 del self.__index_cache[database_name]
00431 return
00432
00433 if not collection_name in self.__index_cache[database_name]:
00434 return
00435
00436 if index_name is None:
00437 del self.__index_cache[database_name][collection_name]
00438 return
00439
00440 if index_name in self.__index_cache[database_name][collection_name]:
00441 del self.__index_cache[database_name][collection_name][index_name]
00442
00443 @property
00444 def host(self):
00445 """Current connected host.
00446
00447 .. versionchanged:: 1.3
00448 ``host`` is now a property rather than a method.
00449 """
00450 return self.__host
00451
00452 @property
00453 def port(self):
00454 """Current connected port.
00455
00456 .. versionchanged:: 1.3
00457 ``port`` is now a property rather than a method.
00458 """
00459 return self.__port
00460
00461 @property
00462 def nodes(self):
00463 """List of all known nodes.
00464
00465 Includes both nodes specified when the :class:`Connection` was
00466 created, as well as nodes discovered through the replica set
00467 discovery mechanism.
00468
00469 .. versionadded:: 1.8
00470 """
00471 return self.__nodes
00472
00473 @property
00474 def slave_okay(self):
00475 """Is it okay for this connection to connect directly to a slave?
00476 """
00477 return self.__slave_okay
00478
00479 def get_document_class(self):
00480 return self.__document_class
00481
00482 def set_document_class(self, klass):
00483 self.__document_class = klass
00484
00485 document_class = property(get_document_class, set_document_class,
00486 doc="""Default class to use for documents
00487 returned on this connection.
00488
00489 .. versionadded:: 1.7
00490 """)
00491
00492 @property
00493 def tz_aware(self):
00494 """Does this connection return timezone-aware datetimes?
00495
00496 See the `tz_aware` parameter to :meth:`Connection`.
00497
00498 .. versionadded:: 1.8
00499 """
00500 return self.__tz_aware
00501
00502 @property
00503 def max_bson_size(self):
00504 """Return the maximum size BSON object the connected server
00505 accepts in bytes. Defaults to 4MB in server < 1.7.4.
00506
00507 .. versionadded:: 1.10
00508 """
00509 return self.__max_bson_size
00510
00511 def __add_hosts_and_get_primary(self, response):
00512 if "hosts" in response:
00513 self.__nodes.update([_str_to_node(h) for h in response["hosts"]])
00514 if "primary" in response:
00515 return _str_to_node(response["primary"])
00516 return False
00517
00518 def __try_node(self, node):
00519 self.disconnect()
00520 self.__host, self.__port = node
00521 try:
00522 response = self.admin.command("ismaster")
00523 self.end_request()
00524
00525 if "maxBsonObjectSize" in response:
00526 self.__max_bson_size = response["maxBsonObjectSize"]
00527
00528
00529
00530
00531 if len(self.__nodes) == 1 and self.__slave_okay:
00532 if response["ismaster"]:
00533 return True
00534 return False
00535
00536 primary = self.__add_hosts_and_get_primary(response)
00537 if response["ismaster"]:
00538 return True
00539 return primary
00540 except:
00541 self.end_request()
00542 return None
00543
00544 def __find_master(self):
00545 """Create a new socket and use it to figure out who the master is.
00546
00547 Sets __host and __port so that :attr:`host` and :attr:`port`
00548 will return the address of the master. Also (possibly) updates
00549 any replSet information.
00550 """
00551
00552
00553 first = iter(self.__nodes).next()
00554
00555 primary = self.__try_node(first)
00556 if primary is True:
00557 return first
00558
00559
00560 if self.__slave_okay and primary is not None:
00561 return first
00562
00563
00564 tried = [first]
00565 if primary:
00566 if self.__try_node(primary) is True:
00567 return primary
00568 tried.append(primary)
00569
00570 nodes = self.__nodes - set(tried)
00571
00572
00573
00574 for node in nodes:
00575 if self.__try_node(node) is True:
00576 return node
00577
00578 raise AutoReconnect("could not find master/primary")
00579
00580 def __connect(self):
00581 """(Re-)connect to Mongo and return a new (connected) socket.
00582
00583 Connect to the master if this is a paired connection.
00584 """
00585 host, port = (self.__host, self.__port)
00586 if host is None or port is None:
00587 host, port = self.__find_master()
00588
00589 try:
00590 sock = socket.socket()
00591 sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
00592 sock.settimeout(self.__network_timeout or _CONNECT_TIMEOUT)
00593 sock.connect((host, port))
00594 sock.settimeout(self.__network_timeout)
00595 return sock
00596 except socket.error:
00597 self.disconnect()
00598 raise AutoReconnect("could not connect to %r" % list(self.__nodes))
00599
00600 def __socket(self):
00601 """Get a socket from the pool.
00602
00603 If it's been > 1 second since the last time we checked out a
00604 socket, we also check to see if the socket has been closed -
00605 this let's us avoid seeing *some*
00606 :class:`~pymongo.errors.AutoReconnect` exceptions on server
00607 hiccups, etc. We only do this if it's been > 1 second since
00608 the last socket checkout, to keep performance reasonable - we
00609 can't avoid those completely anyway.
00610 """
00611 sock = self.__pool.socket()
00612 t = time.time()
00613 if t - self.__last_checkout > 1:
00614 if _closed(sock):
00615 self.disconnect()
00616 sock = self.__pool.socket()
00617 self.__last_checkout = t
00618 return sock
00619
00620 def disconnect(self):
00621 """Disconnect from MongoDB.
00622
00623 Disconnecting will close all underlying sockets in the
00624 connection pool. If the :class:`Connection` is used again it
00625 will be automatically re-opened. Care should be taken to make
00626 sure that :meth:`disconnect` is not called in the middle of a
00627 sequence of operations in which ordering is important. This
00628 could lead to unexpected results.
00629
00630 .. seealso:: :meth:`end_request`
00631 .. versionadded:: 1.3
00632 """
00633 self.__pool = _Pool(self.__connect)
00634 self.__host = None
00635 self.__port = None
00636
00637 def set_cursor_manager(self, manager_class):
00638 """Set this connection's cursor manager.
00639
00640 Raises :class:`TypeError` if `manager_class` is not a subclass of
00641 :class:`~pymongo.cursor_manager.CursorManager`. A cursor manager
00642 handles closing cursors. Different managers can implement different
00643 policies in terms of when to actually kill a cursor that has
00644 been closed.
00645
00646 :Parameters:
00647 - `manager_class`: cursor manager to use
00648 """
00649 manager = manager_class(self)
00650 if not isinstance(manager, CursorManager):
00651 raise TypeError("manager_class must be a subclass of "
00652 "CursorManager")
00653
00654 self.__cursor_manager = manager
00655
00656 def __check_response_to_last_error(self, response):
00657 """Check a response to a lastError message for errors.
00658
00659 `response` is a byte string representing a response to the message.
00660 If it represents an error response we raise OperationFailure.
00661
00662 Return the response as a document.
00663 """
00664 response = helpers._unpack_response(response)
00665
00666 assert response["number_returned"] == 1
00667 error = response["data"][0]
00668
00669 helpers._check_command_response(error, self.disconnect)
00670
00671
00672 if error.get("err", 0) is None:
00673 return error
00674 if error["err"] == "not master":
00675 self.disconnect()
00676 raise AutoReconnect("not master")
00677
00678 if "code" in error:
00679 if error["code"] in [11000, 11001, 12582]:
00680 raise DuplicateKeyError(error["err"])
00681 else:
00682 raise OperationFailure(error["err"], error["code"])
00683 else:
00684 raise OperationFailure(error["err"])
00685
00686 def __check_bson_size(self, message):
00687 """Make sure the message doesn't include BSON documents larger
00688 than the connected server will accept.
00689
00690 :Parameters:
00691 - `message`: message to check
00692 """
00693 if len(message) == 3:
00694 (request_id, data, max_doc_size) = message
00695 if max_doc_size > self.__max_bson_size:
00696 raise InvalidDocument("BSON document too large (%d bytes)"
00697 " - the connected server supports"
00698 " BSON document sizes up to %d"
00699 " bytes." %
00700 (max_doc_size, self.__max_bson_size))
00701 return (request_id, data)
00702 else:
00703
00704
00705 return message
00706
00707 def _send_message(self, message, with_last_error=False):
00708 """Say something to Mongo.
00709
00710 Raises ConnectionFailure if the message cannot be sent. Raises
00711 OperationFailure if `with_last_error` is ``True`` and the
00712 response to the getLastError call returns an error. Return the
00713 response from lastError, or ``None`` if `with_last_error`
00714 is ``False``.
00715
00716 :Parameters:
00717 - `message`: message to send
00718 - `with_last_error`: check getLastError status after sending the
00719 message
00720 """
00721 sock = self.__socket()
00722 try:
00723 (request_id, data) = self.__check_bson_size(message)
00724 sock.sendall(data)
00725
00726
00727
00728
00729 if with_last_error:
00730 response = self.__receive_message_on_socket(1, request_id,
00731 sock)
00732 return self.__check_response_to_last_error(response)
00733 return None
00734 except (ConnectionFailure, socket.error), e:
00735 self.disconnect()
00736 raise AutoReconnect(str(e))
00737
00738 def __receive_data_on_socket(self, length, sock):
00739 """Lowest level receive operation.
00740
00741 Takes length to receive and repeatedly calls recv until able to
00742 return a buffer of that length, raising ConnectionFailure on error.
00743 """
00744 message = ""
00745 while len(message) < length:
00746 chunk = sock.recv(length - len(message))
00747 if chunk == "":
00748 raise ConnectionFailure("connection closed")
00749 message += chunk
00750 return message
00751
00752 def __receive_message_on_socket(self, operation, request_id, sock):
00753 """Receive a message in response to `request_id` on `sock`.
00754
00755 Returns the response data with the header removed.
00756 """
00757 header = self.__receive_data_on_socket(16, sock)
00758 length = struct.unpack("<i", header[:4])[0]
00759 assert request_id == struct.unpack("<i", header[8:12])[0], \
00760 "ids don't match %r %r" % (request_id,
00761 struct.unpack("<i", header[8:12])[0])
00762 assert operation == struct.unpack("<i", header[12:])[0]
00763
00764 return self.__receive_data_on_socket(length - 16, sock)
00765
00766 def __send_and_receive(self, message, sock):
00767 """Send a message on the given socket and return the response data.
00768 """
00769 (request_id, data) = self.__check_bson_size(message)
00770 sock.sendall(data)
00771 return self.__receive_message_on_socket(1, request_id, sock)
00772
00773
00774
00775 def _send_message_with_response(self, message,
00776 _must_use_master=False, **kwargs):
00777 """Send a message to Mongo and return the response.
00778
00779 Sends the given message and returns the response.
00780
00781 :Parameters:
00782 - `message`: (request_id, data) pair making up the message to send
00783 """
00784 sock = self.__socket()
00785
00786 try:
00787 try:
00788 if "network_timeout" in kwargs:
00789 sock.settimeout(kwargs["network_timeout"])
00790 return self.__send_and_receive(message, sock)
00791 except (ConnectionFailure, socket.error), e:
00792 self.disconnect()
00793 raise AutoReconnect(str(e))
00794 finally:
00795 if "network_timeout" in kwargs:
00796 sock.settimeout(self.__network_timeout)
00797
00798 def start_request(self):
00799 """DEPRECATED all operations will start a request.
00800
00801 .. versionchanged:: 1.4
00802 DEPRECATED
00803 """
00804 warnings.warn("the Connection.start_request method is deprecated",
00805 DeprecationWarning)
00806
00807 def end_request(self):
00808 """Allow this thread's connection to return to the pool.
00809
00810 Calling :meth:`end_request` allows the :class:`~socket.socket`
00811 that has been reserved for this thread to be returned to the
00812 pool. Other threads will then be able to re-use that
00813 :class:`~socket.socket`. If your application uses many
00814 threads, or has long-running threads that infrequently perform
00815 MongoDB operations, then judicious use of this method can lead
00816 to performance gains. Care should be taken, however, to make
00817 sure that :meth:`end_request` is not called in the middle of a
00818 sequence of operations in which ordering is important. This
00819 could lead to unexpected results.
00820
00821 One important case is when a thread is dying permanently. It
00822 is best to call :meth:`end_request` when you know a thread is
00823 finished, as otherwise its :class:`~socket.socket` will not be
00824 reclaimed.
00825 """
00826 self.__pool.return_socket()
00827
00828 def __cmp__(self, other):
00829 if isinstance(other, Connection):
00830 return cmp((self.__host, self.__port),
00831 (other.__host, other.__port))
00832 return NotImplemented
00833
00834 def __repr__(self):
00835 if len(self.__nodes) == 1:
00836 return "Connection(%r, %r)" % (self.__host, self.__port)
00837 else:
00838 return "Connection(%r)" % ["%s:%d" % n for n in self.__nodes]
00839
00840 def __getattr__(self, name):
00841 """Get a database by name.
00842
00843 Raises :class:`~pymongo.errors.InvalidName` if an invalid
00844 database name is used.
00845
00846 :Parameters:
00847 - `name`: the name of the database to get
00848 """
00849 return database.Database(self, name)
00850
00851 def __getitem__(self, name):
00852 """Get a database by name.
00853
00854 Raises :class:`~pymongo.errors.InvalidName` if an invalid
00855 database name is used.
00856
00857 :Parameters:
00858 - `name`: the name of the database to get
00859 """
00860 return self.__getattr__(name)
00861
00862 def close_cursor(self, cursor_id):
00863 """Close a single database cursor.
00864
00865 Raises :class:`TypeError` if `cursor_id` is not an instance of
00866 ``(int, long)``. What closing the cursor actually means
00867 depends on this connection's cursor manager.
00868
00869 :Parameters:
00870 - `cursor_id`: id of cursor to close
00871
00872 .. seealso:: :meth:`set_cursor_manager` and
00873 the :mod:`~pymongo.cursor_manager` module
00874 """
00875 if not isinstance(cursor_id, (int, long)):
00876 raise TypeError("cursor_id must be an instance of (int, long)")
00877
00878 self.__cursor_manager.close(cursor_id)
00879
00880 def kill_cursors(self, cursor_ids):
00881 """Send a kill cursors message with the given ids.
00882
00883 Raises :class:`TypeError` if `cursor_ids` is not an instance of
00884 ``list``.
00885
00886 :Parameters:
00887 - `cursor_ids`: list of cursor ids to kill
00888 """
00889 if not isinstance(cursor_ids, list):
00890 raise TypeError("cursor_ids must be a list")
00891 return self._send_message(message.kill_cursors(cursor_ids))
00892
00893 def server_info(self):
00894 """Get information about the MongoDB server we're connected to.
00895 """
00896 return self.admin.command("buildinfo")
00897
00898 def database_names(self):
00899 """Get a list of the names of all databases on the connected server.
00900 """
00901 return [db["name"] for db in
00902 self.admin.command("listDatabases")["databases"]]
00903
00904 def drop_database(self, name_or_database):
00905 """Drop a database.
00906
00907 Raises :class:`TypeError` if `name_or_database` is not an instance of
00908 ``(str, unicode, Database)``
00909
00910 :Parameters:
00911 - `name_or_database`: the name of a database to drop, or a
00912 :class:`~pymongo.database.Database` instance representing the
00913 database to drop
00914 """
00915 name = name_or_database
00916 if isinstance(name, database.Database):
00917 name = name.name
00918
00919 if not isinstance(name, basestring):
00920 raise TypeError("name_or_database must be an instance of "
00921 "(Database, str, unicode)")
00922
00923 self._purge_index(name)
00924 self[name].command("dropDatabase")
00925
00926 def copy_database(self, from_name, to_name,
00927 from_host=None, username=None, password=None):
00928 """Copy a database, potentially from another host.
00929
00930 Raises :class:`TypeError` if `from_name` or `to_name` is not
00931 an instance of :class:`basestring`. Raises
00932 :class:`~pymongo.errors.InvalidName` if `to_name` is not a
00933 valid database name.
00934
00935 If `from_host` is ``None`` the current host is used as the
00936 source. Otherwise the database is copied from `from_host`.
00937
00938 If the source database requires authentication, `username` and
00939 `password` must be specified.
00940
00941 :Parameters:
00942 - `from_name`: the name of the source database
00943 - `to_name`: the name of the target database
00944 - `from_host` (optional): host name to copy from
00945 - `username` (optional): username for source database
00946 - `password` (optional): password for source database
00947
00948 .. note:: Specifying `username` and `password` requires server
00949 version **>= 1.3.3+**.
00950
00951 .. versionadded:: 1.5
00952 """
00953 if not isinstance(from_name, basestring):
00954 raise TypeError("from_name must be an instance of basestring")
00955 if not isinstance(to_name, basestring):
00956 raise TypeError("to_name must be an instance of basestring")
00957
00958 database._check_name(to_name)
00959
00960 command = {"fromdb": from_name, "todb": to_name}
00961
00962 if from_host is not None:
00963 command["fromhost"] = from_host
00964
00965 if username is not None:
00966 nonce = self.admin.command("copydbgetnonce",
00967 fromhost=from_host)["nonce"]
00968 command["username"] = username
00969 command["nonce"] = nonce
00970 command["key"] = helpers._auth_key(nonce, username, password)
00971
00972 return self.admin.command("copydb", **command)
00973
00974 def __iter__(self):
00975 return self
00976
00977 def next(self):
00978 raise TypeError("'Connection' object is not iterable")