From 2f5e8d48b3e98ddb6c7293c0ed06bf71044fdbe7 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 12 Aug 2011 13:33:55 +0200 Subject: [PATCH] [REF] osv: moved (and adapted) vacuum code to osv_memory. bzr revid: vmt@openerp.com-20110812113355-lylavdsc3mqjovrj --- openerp/__init__.py | 3 + .../addons/base/ir/osv_memory_autovacuum.py | 12 ++-- openerp/modules/module.py | 2 + openerp/osv/orm.py | 35 +---------- openerp/osv/osv.py | 60 +++++++++++++++++++ 5 files changed, 71 insertions(+), 41 deletions(-) diff --git a/openerp/__init__.py b/openerp/__init__.py index b7b5fc1b533..b74885674fa 100644 --- a/openerp/__init__.py +++ b/openerp/__init__.py @@ -42,5 +42,8 @@ import tools import wizard import workflow +# The hard-coded super-user id (a.k.a. administrator, or root user). +SUPERUSER = 1 + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/osv_memory_autovacuum.py b/openerp/addons/base/ir/osv_memory_autovacuum.py index b2ab938d740..f15adb77a02 100644 --- a/openerp/addons/base/ir/osv_memory_autovacuum.py +++ b/openerp/addons/base/ir/osv_memory_autovacuum.py @@ -19,18 +19,16 @@ # ############################################################################## -from osv import osv -from osv.orm import orm_memory +import openerp -class osv_memory_autovacuum(osv.osv_memory): +class osv_memory_autovacuum(openerp.osv.osv.osv_memory): + """ Expose the osv_memory.vacuum() method to the cron jobs mechanism. """ _name = 'osv_memory.autovacuum' def power_on(self, cr, uid, context=None): for model in self.pool.obj_list(): obj = self.pool.get(model) - if isinstance(obj, orm_memory): - obj.vaccum(cr, uid) + if obj._transient: + obj.vacuum(cr, uid) return True -osv_memory_autovacuum() - diff --git a/openerp/modules/module.py b/openerp/modules/module.py index 1514e836dd8..6ce0374814f 100644 --- a/openerp/modules/module.py +++ b/openerp/modules/module.py @@ -284,6 +284,8 @@ def init_module_models(cr, module_name, obj_list): cr.commit() for obj in obj_list: obj._auto_end(cr, {'module': module_name}) + if obj._transient: + obj.vacuum(cr, openerp.SUPERUSER) cr.commit() todo.sort() for t in todo: diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 850d88d8460..efd93f75e1b 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -2250,8 +2250,6 @@ class orm_memory(orm_template): _protected = ['read', 'write', 'create', 'default_get', 'perm_read', 'unlink', 'fields_get', 'fields_view_get', 'search', 'name_get', 'distinct_field_get', 'name_search', 'copy', 'import_data', 'search_count', 'exists'] _inherit_fields = {} - _max_count = None - _max_hours = None _check_time = 20 @classmethod @@ -2262,43 +2260,12 @@ class orm_memory(orm_template): super(orm_memory, self).__init__(pool, cr) self.datas = {} self.next_id = 0 - self.check_id = 0 - self._max_count = config.get('osv_memory_count_limit') - self._max_hours = config.get('osv_memory_age_limit') cr.execute('delete from wkf_instance where res_type=%s', (self._name,)) def _check_access(self, uid, object_id, mode): if uid != 1 and self.datas[object_id]['internal.create_uid'] != uid: raise except_orm(_('AccessError'), '%s access is only allowed on your own records for osv_memory objects except for the super-user' % mode.capitalize()) - def vaccum(self, cr, uid, force=False): - """Run the vaccuum cleaning system, expiring and removing old records from the - virtual osv_memory tables if the "max count" or "max age" conditions are enabled - and have been reached. This method can be called very often (e.g. everytime a record - is created), but will only actually trigger the cleanup process once out of - "_check_time" times (by default once out of 20 calls).""" - self.check_id += 1 - if (not force) and (self.check_id % self._check_time): - return True - tounlink = [] - - # Age-based expiration - if self._max_hours: - max = time.time() - self._max_hours * 60 * 60 - for k,v in self.datas.iteritems(): - if v['internal.date_access'] < max: - tounlink.append(k) - self.unlink(cr, ROOT_USER_ID, tounlink) - - # Count-based expiration - if self._max_count and len(self.datas) > self._max_count: - # sort by access time to remove only the first/oldest ones in LRU fashion - records = self.datas.items() - records.sort(key=lambda x:x[1]['internal.date_access']) - self.unlink(cr, ROOT_USER_ID, [x[0] for x in records[:len(self.datas)-self._max_count]]) - - return True - def read(self, cr, user, ids, fields_to_read=None, context=None, load='_classic_read'): if not context: context = {} @@ -2352,7 +2319,7 @@ class orm_memory(orm_template): return object_id def create(self, cr, user, vals, context=None): - self.vaccum(cr, user) + self.vacuum(cr, user) self.next_id += 1 id_new = self.next_id diff --git a/openerp/osv/osv.py b/openerp/osv/osv.py index c624bd7358f..b231abd54ab 100644 --- a/openerp/osv/osv.py +++ b/openerp/osv/osv.py @@ -22,11 +22,13 @@ #.apidoc title: Objects Services (OSV) import orm +import openerp import openerp.netsvc as netsvc import openerp.pooler as pooler import openerp.sql_db as sql_db import logging from psycopg2 import IntegrityError, errorcodes +from openerp.tools.config import config from openerp.tools.func import wraps from openerp.tools.translate import translate from openerp.osv.orm import MetaModel @@ -203,12 +205,70 @@ class osv_memory(orm.orm): """ Deprecated class. """ __metaclass__ = MetaModel _register = False # Set to false if the model shouldn't be automatically discovered. + _transient = True + _max_count = None + _max_hours = None + _check_time = 20 + + def __init__(self, pool, cr): + super(osv_memory, self).__init__(pool, cr) + self.check_id = 0 + self._max_count = config.get('osv_memory_count_limit') + self._max_hours = config.get('osv_memory_age_limit') + + def _clean_transient_rows_older_than(self, cr, seconds): + if not self._log_access: + self.logger = logging.getLogger('orm').warning( + "Transient model without write_date: %s" % (self._name,)) + return + + cr.execute("SELECT id FROM " + self._table + " WHERE " + "COALESCE(write_date, create_date, now())::timestamp < " + "(now() - interval %s)", ("%s seconds" % seconds,)) + ids = [x[0] for x in cr.fetchall()] + self.unlink(cr, openerp.SUPERUSER, ids) + + def _clean_old_transient_rows(self, cr, count): + if not self._log_access: + self.logger = logging.getLogger('orm').warning( + "Transient model without write_date: %s" % (self._name,)) + return + + cr.execute( + "SELECT id, COALESCE(write_date, create_date, now())::timestamp" + " AS t FROM " + self._table + + " ORDER BY t LIMIT %s", (count,)) + ids = [x[0] for x in cr.fetchall()] + self.unlink(cr, openerp.SUPERUSER, ids) + + def vacuum(self, cr, uid, force=False): + """ Run the vacuum cleaner, i.e. unlink old records from the + virtual osv_memory tables if the "max count" or "max age" conditions are enabled + and have been reached. This method can be called very often (e.g. everytime a record + is created), but will only actually trigger the cleanup process once out of + "_check_time" times (by default once out of 20 calls).""" + self.check_id += 1 + if (not force) and (self.check_id % self._check_time): + self.check_id = 0 + return True + tounlink = [] + + # Age-based expiration + if self._max_hours: + self._clean_transient_rows_older_than(cr, self._max_hours * 60 * 60) + + # Count-based expiration + if self._max_count: + self._clean_old_transient_rows(cr, self._max_count) + + return True class osv(orm.orm): """ Deprecated class. """ __metaclass__ = MetaModel _register = False # Set to false if the model shouldn't be automatically discovered. + _transient = False def start_object_proxy():