diff --git a/CHANGELOG b/CHANGELOG index 0ac3237dce..80bf81c732 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Refresh pool of other processes * Add clear_all method to Cache * Support Genshi element directives in HTML editor * Add firstline tool diff --git a/trytond/cache.py b/trytond/cache.py index 96107a97fd..6475a590fc 100644 --- a/trytond/cache.py +++ b/trytond/cache.py @@ -16,6 +16,7 @@ from sql.functions import CurrentTimestamp, Function from trytond import backend from trytond.config import config +from trytond.pool import Pool from trytond.transaction import Transaction from trytond.tools import resolve, grouped_slice @@ -43,6 +44,15 @@ def freeze(o): return o +def _get_modules(cursor): + ir_module = Table('ir_module') + cursor.execute(*ir_module.select( + ir_module.name, + where=ir_module.state.in_( + ['activated', 'to upgrade', 'to remove']))) + return {m for m, in cursor} + + class BaseCache(object): _instances = {} @@ -195,6 +205,7 @@ class MemoryCache(BaseCache): timestamps = {} for timestamp, name in cursor.fetchall(): timestamps[name] = timestamp + modules = _get_modules(cursor) finally: database.put_connection(connection) for name, timestamp in timestamps.items(): @@ -205,6 +216,7 @@ class MemoryCache(BaseCache): inst_timestamp = inst._timestamp.get(dbname) if not inst_timestamp or timestamp > inst_timestamp: inst._clear(dbname, timestamp) + Pool(dbname).refresh(modules) cls._clean_last = datetime.now() def sync_since(self, value): @@ -291,6 +303,21 @@ class MemoryCache(BaseCache): inst._database_cache.pop(dbname, None) inst._transaction_lower.pop(dbname, None) + @classmethod + def refresh_pool(cls, transaction): + database = transaction.database + dbname = database.name + if not _clear_timeout and database.has_channel(): + database = backend.Database(dbname) + conn = database.get_connection() + try: + cursor = conn.cursor() + cursor.execute( + 'NOTIFY "%s", %%s' % cls._channel, ('refresh pool',)) + conn.commit() + finally: + database.put_connection(conn) + @classmethod def _listen(cls, dbname): database = backend.Database(dbname) @@ -313,7 +340,9 @@ class MemoryCache(BaseCache): conn.poll() while conn.notifies: notification = conn.notifies.pop() - if notification.payload: + if notification.payload == 'refresh pool': + Pool(dbname).refresh(_get_modules(cursor)) + elif notification.payload: reset = json.loads(notification.payload) for name in reset: inst = cls._instances[name] diff --git a/trytond/ir/module.py b/trytond/ir/module.py index b359a7e2a0..4d28b6da2c 100644 --- a/trytond/ir/module.py +++ b/trytond/ir/module.py @@ -5,6 +5,7 @@ from functools import wraps from sql.operators import NotIn +from trytond.cache import Cache from trytond.exceptions import UserError from trytond.i18n import gettext from trytond.model import ModelView, ModelSQL, fields, Unique, sequence_ordered @@ -557,7 +558,8 @@ class ModuleActivateUpgrade(Wizard): pool = Pool() Module = pool.get('ir.module') Lang = pool.get('ir.lang') - with Transaction().new_transaction(): + transaction = Transaction() + with transaction.new_transaction(): modules = Module.search([ ('state', 'in', ['to upgrade', 'to remove', 'to activate']), ]) @@ -568,6 +570,7 @@ class ModuleActivateUpgrade(Wizard): lang = [x.code for x in langs] if update: pool.init(update=update, lang=lang) + Cache.refresh_pool(transaction) return 'done' diff --git a/trytond/modules/__init__.py b/trytond/modules/__init__.py index 6fad3d12d5..01524a0773 100644 --- a/trytond/modules/__init__.py +++ b/trytond/modules/__init__.py @@ -302,6 +302,7 @@ def load_module_graph(graph, pool, update=None, lang=None): # Ensure cache is clear for other instances Cache.clear_all() + Cache.refresh_pool(transaction) logger.info('all modules loaded') diff --git a/trytond/pool.py b/trytond/pool.py index 913096ed8a..b85020eb0c 100644 --- a/trytond/pool.py +++ b/trytond/pool.py @@ -113,12 +113,12 @@ class Pool(object): with cls._lock: if database_name in cls._instances: del cls._instances[database_name] - lock = cls._locks.get(database_name) - if not lock: - return - with lock: - if database_name in cls._pool: - del cls._pool[database_name] + lock = cls._locks.get(database_name) + if not lock: + return + with lock: + if database_name in cls._pool: + del cls._pool[database_name] @classmethod def database_list(cls): @@ -271,6 +271,10 @@ class Pool(object): cls.__name__, (mixin, cls), {'__slots__': ()}) self.add(cls, type=type_) + def refresh(self, modules): + if set(self._modules) != modules: + self.stop(self.database_name) + def isregisteredby(obj, module, type_='model'): pool = Pool()