source: indico/indico/MaKaC/common/db.py @ 23945f

burotelhello-world-walkthroughipv6v0.98-seriesv0.98.2v0.98.3v0.98b1v0.98b2v0.99v1.0v1.1
Last change on this file since 23945f was 23945f, checked in by Pedro Ferreira <jose.pedro.ferreira@…>, 2 years ago

[FIX] Further improvements in scheduler DB

  • Property mode set to 100644
File size: 7.1 KB
Line 
1# -*- coding: utf-8 -*-
2##
3##
4## This file is part of CDS Indico.
5## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
6##
7## CDS Indico is free software; you can redistribute it and/or
8## modify it under the terms of the GNU General Public License as
9## published by the Free Software Foundation; either version 2 of the
10## License, or (at your option) any later version.
11##
12## CDS Indico is distributed in the hope that it will be useful, but
13## WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15## General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
19## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
21"""This file contains the implementation of some classes dealing with the DB
22    so it's usage is easier and more transparent to the rest of the application
23"""
24import os
25import sys
26import threading
27import pkg_resources
28from contextlib import contextmanager
29
30from ZEO.ClientStorage import ClientStorage
31from ZODB.DB import DB
32import transaction
33import ZODB
34
35from MaKaC.consoleScripts.installBase import getIndicoInstallMode
36skip_imports = getIndicoInstallMode()
37
38if not skip_imports:
39    from MaKaC.common.logger import Logger
40    from MaKaC.i18n import _
41
42
43class MaKaCDB(DB):
44    """Subclass of ZODB.DB necessary to remove possible existing dependencies
45        from IC"""
46
47    def classFactory(self, connection, modulename, globalname):
48        if globalname=="PersistentMapping":
49            modulename="persistent.mapping"
50        elif globalname=="PersistentList":
51            modulename="persistent.list"
52        elif modulename.startswith("IndexedCatalog.BTrees."):
53            modulename="BTrees.%s"%modulename[22:]
54        return DB.classFactory(self, connection, modulename, globalname)
55
56
57class DBMgr:
58    """This class provides the access point to the Shelf (every client will
59        use this class in order to obtain a shelf) and some mechanism to
60        ensure there is only one connection opened to the DB during a single
61        request.
62        This class must not be instantiated, an instance can be obtained
63        though the "getInstance" method (implements the singleton pattern
64        to ensure unicity)
65        Needs to be checked if the class (static) attribute _instance is
66        thread-safe: as it is shared by all the objects of this class,
67        it could provoke concurrency troubles having 2 threads using the db
68        connection at the same time. However, the model under which we are
69        programming is not multi-threaded (mod_python seems to run different
70        interpreters for each apache subprocess, see mod_python doc section
71        4.1) so this thechnique can be used. This has to be taken into account
72        when migrating the system to a multi-threading environment.
73    """
74    _instance = None
75
76    def __init__( self, hostname=None, port=None ):
77        import Configuration # Please leave this import here, db.py is imported during installation process
78        cfg = Configuration.Config.getInstance()
79
80        if not hostname:
81            hostname = cfg.getDBConnectionParams()[0]
82        if not port:
83            port = cfg.getDBConnectionParams()[1]
84
85        self._storage=ClientStorage((hostname, port), username=cfg.getDBUserName(), password=cfg.getDBPassword(), realm=cfg.getDBRealm())
86        self._db=MaKaCDB(self._storage)
87        self._conn={}
88
89    @classmethod
90    def getInstance( cls, *args, **kwargs ):
91        if cls._instance == None:
92            Logger.get('dbmgr').debug('cls._instance is None')
93            cls._instance=DBMgr(*args, **kwargs)
94        return cls._instance
95
96    @classmethod
97    def setInstance( cls, dbInstance ):
98        cls._instance = dbInstance
99
100    @staticmethod
101    def _getUniqueIdentifier():
102        return threading._get_ident()
103
104    def _getConnObject(self):
105        tid = DBMgr._getUniqueIdentifier()
106        return self._conn[tid]
107
108    def _setConnObject(self, obj):
109        tid = DBMgr._getUniqueIdentifier()
110        self._conn[tid] = obj
111
112    def _delConnObject(self):
113        tid = DBMgr._getUniqueIdentifier()
114        del self._conn[tid]
115
116    def startRequest( self ):
117        """Initialise the DB and starts a new transaction.
118        """
119
120        tid = DBMgr._getUniqueIdentifier()
121
122        self._conn[tid] = self._db.open()
123        Logger.get('dbmgr').debug('Allocated connection for %s - table size is %s' % \
124                                  (tid, len(self._conn)))
125
126    def endRequest( self, commit=True ):
127        """Closes the DB and commits changes.
128        """
129        if commit:
130            self.commit()
131        else:
132            self.abort()
133
134        #modification vendredi 010907
135#        try:
136#            self._conn.close()
137#            self._conn=None
138#        except:
139#            pass
140
141        self._getConnObject().close()
142        self._delConnObject()
143
144    def getDBConnection( self ):
145        return self._getConnObject()
146
147    def isConnected( self ):
148        tid = DBMgr._getUniqueIdentifier()
149
150        return tid in self._conn
151
152    def getDBConnCache(self):
153        conn = self._getConnObject()
154        return conn._cache
155
156    def getDBClassFactory(self):
157        return self._db.classFactory
158
159    def commit(self, sub=False):
160        if (sub):
161            transaction.savepoint()
162        else:
163            transaction.commit()
164
165    def commitZODBOld(self, sub=False):
166        transaction.commit(sub)
167
168    def abort(self):
169        transaction.abort()
170
171    def sync(self):
172        self._getConnObject().sync()
173
174    def pack( self, days=1 ):
175        self._storage.pack(days=days)
176
177    def undoInfo(self, stepNumber=0):
178        # One step is made of 1000 transactions. First step is 0 and returns
179        # transactions 0 to 999.
180        return self._db.undoInfo(stepNumber*1000, (stepNumber+1)*1000)
181
182    def undo(self, trans_id):
183        self._db.undo(trans_id)
184
185    def getDBSize( self ):
186        """Return an approximate size of the database, in bytes."""
187        return self._storage.getSize()
188
189    def loadObject(self, oid, version):
190        return self._storage.load(oid, version)
191
192    def storeObject(self, oid, serial, data, version, trans):
193        return self._storage.store(oid, serial, data, version, trans)
194
195    def tpcBegin(self, trans):
196        self._storage.tpc_begin(trans)
197
198    def tpcVote(self, trans):
199        self._storage.tpc_vote(trans)
200
201    def tpcFinish(self, trans):
202        self._storage.tpc_finish(trans)
203
204    @contextmanager
205    def transaction(self):
206        """
207        context manager (`with`)
208        """
209        yield
210        self.commit()
211
212    # ZODB version check
213    try:
214        zodbPkg = pkg_resources.require('ZODB3')[0]
215        zodbVersion = zodbPkg.parsed_version
216        zodbVersion = (int(zodbVersion[0]), int(zodbVersion[1]))
217    except pkg_resources.DistributionNotFound:
218        # Very old versions, in which ZODB didn't register
219        # with pkg_resources
220        import ZODB
221        zodbVersion = ZODB.__version__.split('.')
222
223    if int(zodbVersion[0]) < 3:
224        raise Exception("ZODB 3 required! %s found" % zodbPkg.version)
225    elif int(zodbVersion[1]) < 7:
226        commit = commitZODBOld
Note: See TracBrowser for help on using the repository browser.