Browse Source

MongoDB datasource enhancement

- Enables connections saving & auto cleaning
- Preparing possibility to declare a datasource as read only
Yann Weber 8 years ago
parent
commit
d9399bc64d

+ 2
- 1
plugins/mongodb_datasource/confspec.py View File

@@ -4,10 +4,11 @@ from lodel.settings.validator import SettingValidator
4 4
 
5 5
 CONFSPEC = {
6 6
     'lodel2.datasource.mongodb_datasource.*':{
7
+        'read_only': (True, SettingValidator('bool')),
7 8
         'host': ('localhost', SettingValidator('host')),
8 9
         'port': (None, SettingValidator('string')),
9 10
         'db_name':('lodel', SettingValidator('string')),
10 11
         'username': (None, SettingValidator('string')),
11 12
         'password': (None, SettingValidator('string'))
12 13
     }
13
-}
14
+}

+ 57
- 5
plugins/mongodb_datasource/main.py View File

@@ -11,13 +11,23 @@ import urllib
11 11
 
12 12
 from lodel import logger
13 13
 
14
-from .utils import mongodbconnect, object_collection_name, MONGODB_SORT_OPERATORS_MAP
14
+from .utils import mongodbconnect, object_collection_name, \
15
+    connect, MONGODB_SORT_OPERATORS_MAP
15 16
 
16 17
 class MongoDbDataSourceError(Exception):
17 18
     pass
18 19
 
19 20
 class MongoDbDatasource(object):
20 21
     
22
+    ##@brief Stores existing connections
23
+    #
24
+    #The key of this dict is a hash of the connection string + ro parameter.
25
+    #The value is a dict with 2 keys :
26
+    # - conn_count : the number of instanciated datasource that use this
27
+    #connection
28
+    # - db : the pymongo database object instance
29
+    _connections = dict()
30
+
21 31
     ##@brief Mapping from lodel2 operators to mongodb operator
22 32
     lodel2mongo_op_map = {
23 33
         '=':'$eq', '<=':'$lte', '>=':'$gte', '!=':'$ne', '<':'$lt',
@@ -26,10 +36,34 @@ class MongoDbDatasource(object):
26 36
     mongo_op_re = ['$in', '$nin']
27 37
     wildcard_re = re.compile('[^\\\\]\*')
28 38
 
29
-    ## @brief instanciates a database object given a connection name
30
-    # @param connection_name str
31
-    def __init__(self, connection_name):
32
-        self.r_database = mongodbconnect(connection_name)
39
+    ##@brief instanciates a database object given a connection name
40
+    #@param host str : hostname or IP
41
+    #@param port int : mongodb listening port
42
+    #@param db_name str
43
+    #@param username str
44
+    #@param password str
45
+    #@param ro bool : If True the Datasource is for read only, else the
46
+    #Datasource is write only !
47
+    def __init__(self, host, port, db_name, username, password, read_only = False):
48
+        ##@brief Connections infos that can be kept securly
49
+        self.__db_infos = {'host': host, 'port': port, 'db_name': db_name}
50
+        ##@brief Is the instance read only ? (if not it's write only)
51
+        self.__read_only = bool(read_only)
52
+        ##@brief Uniq ID for mongodb connection
53
+        self.__conn_hash= None
54
+        ##@brief Stores the connection to MongoDB
55
+        self.database = self.__connect(username, password)
56
+
57
+    ##@brief Destructor that attempt to close connection to DB
58
+    #
59
+    #Decrease the conn_count of associated MongoDbDatasource::_connections
60
+    #item. If it reach 0 close the connection to the db
61
+    #@see MongoDbDatasource::__connect()
62
+    def __del__(self):
63
+        self._connections[self.__conn_hash]['conn_count'] -= 1
64
+        if self._connections[self.__conn_hash]['conn_count'] <= 0:
65
+            self._connections[self.__conn_hash]['db'].close()
66
+            del(self._connections[self.__conn_hash])
33 67
 
34 68
     ##@brief returns a selection of documents from the datasource
35 69
     #@param target Emclass
@@ -131,6 +165,24 @@ class MongoDbDatasource(object):
131 165
         res = self.__collection.insert_many(datas_list)
132 166
         return list(result.inserted_ids)
133 167
     
168
+    ##@brief Connect to database
169
+    #@not this method avoid opening two times the same connection using
170
+    #MongoDbDatasource::_connections static attribute
171
+    #@param host str : hostname or IP
172
+    #@param port int : mongodb listening port
173
+    #@param db_name str
174
+    #@param username str
175
+    #@param password str
176
+    #@param ro bool : If True the Datasource is for read only, else the
177
+    def __connect(self, username, password, ro):
178
+        conn_string = connection_string(
179
+            username = username, password = password, **self.__db_infos)
180
+        conn_string += "__ReadOnly__:"+self.__read_only
181
+        self.__conf_hash = conn_h = hash(conn_string)
182
+        if conn_h in self._connections:
183
+            self._connections[conn_h]['conn_count'] += 1
184
+            return self._connections[conn_h]['db']
185
+
134 186
     ##@brief Return a pymongo collection given a LeObject child class
135 187
     #@param leobject LeObject child class (no instance)
136 188
     #return a pymongo.collection instance

+ 9
- 2
plugins/mongodb_datasource/utils.py View File

@@ -46,12 +46,19 @@ def get_connection_args(connnection_name='default'):
46 46
 # @return MongoClient
47 47
 def mongodbconnect(connection_name):
48 48
     login, password, host, port, dbname = get_connection_args(connection_name)
49
-    connection_string = 'mongodb://%s:%s@%s:%s' % (login, password, host, port)
50
-    connection = MongoClient(connection_string)
49
+    return connect(host, port, db_name, username, password)
50
+
51
+def connection_string(host, port, db_name, username, password):
52
+    return 'mongodb://%s:%s@%s:%s' % (login, password, host, port)
53
+
54
+def connect(host, port, db_name, username, password):
55
+    connection = MongoClient(
56
+        connection_string(host, port, db_name, username, password))
51 57
     database = connection[dbname]
52 58
     return database
53 59
 
54 60
 
61
+
55 62
 ## @brief Returns a collection name given a EmClass
56 63
 # @param class_object EmClass
57 64
 # @return str

Loading…
Cancel
Save