root/galaxy-central/eggs/Beaker-1.4-py2.6.egg/beaker/ext/database.py @ 3

リビジョン 3, 6.0 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1import cPickle
2import logging
3import pickle
4from datetime import datetime
5
6from beaker.container import OpenResourceNamespaceManager, Container
7from beaker.exceptions import InvalidCacheBackendError, MissingCacheParameter
8from beaker.synchronization import file_synchronizer, null_synchronizer
9from beaker.util import verify_directory, SyncDict
10
11sa_version = None
12
13log = logging.getLogger(__name__)
14
15try:
16    import sqlalchemy as sa
17    import sqlalchemy.pool as pool
18    from sqlalchemy import types
19    sa_version = '0.3'
20except ImportError:
21    raise InvalidCacheBackendError("Database cache backend requires the 'sqlalchemy' library")
22
23if not hasattr(sa, 'BoundMetaData'):
24    sa_version = '0.4'
25
26class DatabaseNamespaceManager(OpenResourceNamespaceManager):
27    metadatas = SyncDict()
28    tables = SyncDict()
29   
30    def __init__(self, namespace, url=None, sa_opts=None, optimistic=False,
31                 table_name='beaker_cache', data_dir=None, lock_dir=None,
32                 **params):
33        """Creates a database namespace manager
34       
35        ``url``
36            SQLAlchemy compliant db url
37        ``sa_opts``
38            A dictionary of SQLAlchemy keyword options to initialize the engine
39            with.
40        ``optimistic``
41            Use optimistic session locking, note that this will result in an
42            additional select when updating a cache value to compare version
43            numbers.
44        ``table_name``
45            The table name to use in the database for the cache.
46        """
47        OpenResourceNamespaceManager.__init__(self, namespace)
48       
49        if sa_opts is None:
50            sa_opts = params
51
52        if lock_dir:
53            self.lock_dir = lock_dir
54        elif data_dir:
55            self.lock_dir = data_dir + "/container_db_lock"
56        if self.lock_dir:
57            verify_directory(self.lock_dir)           
58       
59        # Check to see if the table's been created before
60        url = url or sa_opts['sa.url']
61        table_key = url + table_name
62        def make_cache():
63            # Check to see if we have a connection pool open already
64            meta_key = url + table_name
65            def make_meta():
66                if sa_version == '0.3':
67                    if url.startswith('mysql') and not sa_opts:
68                        sa_opts['poolclass'] = pool.QueuePool
69                    engine = sa.create_engine(url, **sa_opts)
70                    meta = sa.BoundMetaData(engine)
71                else:
72                    # SQLAlchemy pops the url, this ensures it sticks around
73                    # later
74                    sa_opts['sa.url'] = url
75                    engine = sa.engine_from_config(sa_opts, 'sa.')
76                    meta = sa.MetaData()
77                    meta.bind = engine
78                return meta
79            meta = DatabaseNamespaceManager.metadatas.get(meta_key, make_meta)
80            # Create the table object and cache it now
81            cache = sa.Table(table_name, meta,
82                             sa.Column('id', types.Integer, primary_key=True),
83                             sa.Column('namespace', types.String(255), nullable=False),
84                             sa.Column('accessed', types.DateTime, nullable=False),
85                             sa.Column('created', types.DateTime, nullable=False),
86                             sa.Column('data', types.PickleType, nullable=False),
87                             sa.UniqueConstraint('namespace')
88            )
89            cache.create(checkfirst=True)
90            return cache
91        self.hash = {}
92        self._is_new = False
93        self.loaded = False
94        self.cache = DatabaseNamespaceManager.tables.get(table_key, make_cache)
95   
96    def get_access_lock(self):
97        return null_synchronizer()
98
99    def get_creation_lock(self, key):
100        return file_synchronizer(
101            identifier ="databasecontainer/funclock/%s" % self.namespace,
102            lock_dir = self.lock_dir)
103
104    def do_open(self, flags):
105        # If we already loaded the data, don't bother loading it again
106        if self.loaded:
107            self.flags = flags
108            return
109       
110        cache = self.cache
111        result = sa.select([cache.c.data],
112                           cache.c.namespace==self.namespace
113                          ).execute().fetchone()
114        if not result:
115            self._is_new = True
116            self.hash = {}
117        else:
118            self._is_new = False
119            try:
120                self.hash = result['data']
121            except (IOError, OSError, EOFError, cPickle.PickleError,
122                    pickle.PickleError):
123                log.debug("Couln't load pickle data, creating new storage")
124                self.hash = {}
125                self._is_new = True
126        self.flags = flags
127        self.loaded = True
128   
129    def do_close(self):
130        if self.flags is not None and (self.flags == 'c' or self.flags == 'w'):
131            cache = self.cache
132            if self._is_new:
133                cache.insert().execute(namespace=self.namespace, data=self.hash,
134                                       accessed=datetime.now(),
135                                       created=datetime.now())
136                self._is_new = False
137            else:
138                cache.update(cache.c.namespace==self.namespace).execute(
139                    data=self.hash, accessed=datetime.now())
140        self.flags = None
141   
142    def do_remove(self):
143        cache = self.cache
144        cache.delete(cache.c.namespace==self.namespace).execute()
145        self.hash = {}
146       
147        # We can retain the fact that we did a load attempt, but since the
148        # file is gone this will be a new namespace should it be saved.
149        self._is_new = True
150
151    def __getitem__(self, key):
152        return self.hash[key]
153
154    def __contains__(self, key):
155        return self.hash.has_key(key)
156       
157    def __setitem__(self, key, value):
158        self.hash[key] = value
159
160    def __delitem__(self, key):
161        del self.hash[key]
162
163    def keys(self):
164        return self.hash.keys()
165
166class DatabaseContainer(Container):
167    namespace_manager = DatabaseNamespaceManager
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。