[REF] osv: moved (and adapted) vacuum code to osv_memory.

bzr revid: vmt@openerp.com-20110812113355-lylavdsc3mqjovrj
This commit is contained in:
Vo Minh Thu 2011-08-12 13:33:55 +02:00
parent 44d41334d7
commit 2f5e8d48b3
5 changed files with 71 additions and 41 deletions

View File

@ -42,5 +42,8 @@ import tools
import wizard import wizard
import workflow 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: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -19,18 +19,16 @@
# #
############################################################################## ##############################################################################
from osv import osv import openerp
from osv.orm import orm_memory
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' _name = 'osv_memory.autovacuum'
def power_on(self, cr, uid, context=None): def power_on(self, cr, uid, context=None):
for model in self.pool.obj_list(): for model in self.pool.obj_list():
obj = self.pool.get(model) obj = self.pool.get(model)
if isinstance(obj, orm_memory): if obj._transient:
obj.vaccum(cr, uid) obj.vacuum(cr, uid)
return True return True
osv_memory_autovacuum()

View File

@ -284,6 +284,8 @@ def init_module_models(cr, module_name, obj_list):
cr.commit() cr.commit()
for obj in obj_list: for obj in obj_list:
obj._auto_end(cr, {'module': module_name}) obj._auto_end(cr, {'module': module_name})
if obj._transient:
obj.vacuum(cr, openerp.SUPERUSER)
cr.commit() cr.commit()
todo.sort() todo.sort()
for t in todo: for t in todo:

View File

@ -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'] _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 = {} _inherit_fields = {}
_max_count = None
_max_hours = None
_check_time = 20 _check_time = 20
@classmethod @classmethod
@ -2262,43 +2260,12 @@ class orm_memory(orm_template):
super(orm_memory, self).__init__(pool, cr) super(orm_memory, self).__init__(pool, cr)
self.datas = {} self.datas = {}
self.next_id = 0 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,)) cr.execute('delete from wkf_instance where res_type=%s', (self._name,))
def _check_access(self, uid, object_id, mode): def _check_access(self, uid, object_id, mode):
if uid != 1 and self.datas[object_id]['internal.create_uid'] != uid: 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()) 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'): def read(self, cr, user, ids, fields_to_read=None, context=None, load='_classic_read'):
if not context: if not context:
context = {} context = {}
@ -2352,7 +2319,7 @@ class orm_memory(orm_template):
return object_id return object_id
def create(self, cr, user, vals, context=None): def create(self, cr, user, vals, context=None):
self.vaccum(cr, user) self.vacuum(cr, user)
self.next_id += 1 self.next_id += 1
id_new = self.next_id id_new = self.next_id

View File

@ -22,11 +22,13 @@
#.apidoc title: Objects Services (OSV) #.apidoc title: Objects Services (OSV)
import orm import orm
import openerp
import openerp.netsvc as netsvc import openerp.netsvc as netsvc
import openerp.pooler as pooler import openerp.pooler as pooler
import openerp.sql_db as sql_db import openerp.sql_db as sql_db
import logging import logging
from psycopg2 import IntegrityError, errorcodes from psycopg2 import IntegrityError, errorcodes
from openerp.tools.config import config
from openerp.tools.func import wraps from openerp.tools.func import wraps
from openerp.tools.translate import translate from openerp.tools.translate import translate
from openerp.osv.orm import MetaModel from openerp.osv.orm import MetaModel
@ -203,12 +205,70 @@ class osv_memory(orm.orm):
""" Deprecated class. """ """ Deprecated class. """
__metaclass__ = MetaModel __metaclass__ = MetaModel
_register = False # Set to false if the model shouldn't be automatically discovered. _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): class osv(orm.orm):
""" Deprecated class. """ """ Deprecated class. """
__metaclass__ = MetaModel __metaclass__ = MetaModel
_register = False # Set to false if the model shouldn't be automatically discovered. _register = False # Set to false if the model shouldn't be automatically discovered.
_transient = False
def start_object_proxy(): def start_object_proxy():