1 /** 2 MongoClient class doing connection management. Usually this is a main entry point 3 for client code. 4 5 Copyright: © 2012 Sönke Ludwig 6 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 7 Authors: Sönke Ludwig 8 */ 9 module vibe.db.mongo.client; 10 11 public import vibe.db.mongo.collection; 12 public import vibe.db.mongo.database; 13 14 import vibe.core.connectionpool; 15 import vibe.core.log; 16 import vibe.db.mongo.connection; 17 import vibe.db.mongo.settings; 18 19 import core.thread; 20 21 import std.conv; 22 import std.string; 23 import std.range; 24 25 /** 26 Represents a connection to a MongoDB server. 27 28 Note that this class uses a ConnectionPool internally to create and reuse 29 network connections to the server as necessary. It should be reused for all 30 fibers in a thread for optimum performance in high concurrency scenarios. 31 */ 32 final class MongoClient { 33 @safe: 34 35 private { 36 ConnectionPool!MongoConnection m_connections; 37 } 38 39 package this(string host, ushort port) 40 { 41 this("mongodb://" ~ host ~ ":" ~ to!string(port) ~ "/?safe=true"); 42 } 43 44 /** 45 Initializes a MongoDB client using a URL. 46 47 The URL must be in the form documented at 48 $(LINK http://www.mongodb.org/display/DOCS/Connections) which is: 49 50 mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]] 51 52 Throws: 53 An exception if the URL cannot be parsed as a valid MongoDB URL. 54 */ 55 package this(string url) 56 { 57 MongoClientSettings settings; 58 auto goodUrl = parseMongoDBUrl(settings, url); 59 if(!goodUrl) throw new Exception("Unable to parse mongodb URL: " ~ url); 60 this(settings); 61 } 62 63 package this(MongoClientSettings settings) 64 { 65 m_connections = new ConnectionPool!MongoConnection({ 66 auto ret = new MongoConnection(settings); 67 try ret.connect(); 68 catch (Exception e) { 69 // avoid leaking the connection to the GC, which might 70 // destroy it during shutdown when all of vibe.d has 71 // already been destroyed, which in turn causes a null 72 // pointer 73 () @trusted { destroy(ret); } (); 74 throw e; 75 } 76 return ret; 77 }, 78 settings.maxConnections 79 ); 80 81 // force a connection to cause an exception for wrong URLs 82 lockConnection(); 83 } 84 85 /** Disconnects all currently unused connections to the server. 86 */ 87 void cleanupConnections() 88 { 89 m_connections.removeUnused((conn) nothrow @safe { 90 try conn.disconnect(); 91 catch (Exception e) { 92 logWarn("Error thrown during MongoDB connection close: %s", e.msg); 93 try () @trusted { logDebug("Full error: %s", e.toString()); } (); 94 catch (Exception e) {} 95 } 96 }); 97 } 98 99 /** 100 Accesses a collection using an absolute path. 101 102 The full database.collection path must be specified. To access 103 collections using a path relative to their database, use getDatabase in 104 conjunction with MongoDatabase.opIndex. 105 106 Returns: 107 MongoCollection for the given combined database and collection name (path) 108 109 Examples: 110 --- 111 auto col = client.getCollection("test.collection"); 112 --- 113 */ 114 MongoCollection getCollection(string path) 115 { 116 return MongoCollection(this, path); 117 } 118 119 /** 120 Returns an object representing the specified database. 121 122 The returned object allows to access the database entity (which contains 123 a set of collections). There are two main use cases: 124 125 1. Accessing collections using a relative path 126 127 2. Performing service commands on the database itself 128 129 Note that there is no performance gain in accessing collections via a 130 relative path compared to getCollection and an absolute path. 131 132 Returns: 133 MongoDatabase instance representing requested database 134 135 Examples: 136 --- 137 auto db = client.getDatabase("test"); 138 auto coll = db["collection"]; 139 --- 140 */ 141 MongoDatabase getDatabase(string dbName) 142 { 143 return MongoDatabase(this, dbName); 144 } 145 146 147 148 /** 149 Return a handle to all databases of the server. 150 151 Returns: 152 An input range of $(D MongoDatabase) objects. 153 154 Examples: 155 --- 156 auto names = client.getDatabaseNames(); 157 writeln("Current databases are: ", names); 158 --- 159 */ 160 auto getDatabases()() 161 { 162 import std.algorithm : map; 163 return lockConnection.listDatabases() 164 .map!(info => MongoDatabase(this, info.name)); 165 } 166 167 package auto lockConnection() { return m_connections.lockConnection(); } 168 }