[IMP] core: allow profiling & rollback of models population
Profiling: creation of ir.profile records for each models population Rollback: allow triggering multiple times the same population, without any risk of records conflicts (& having to recreated a clean database) Note: those two options are mostly recommended for small models population. Indeed, profiling slows down the population, and large/medium population is already quite slow for some models (and it seems that the rollback breaks as well for some advanced models). Part-of: odoo/odoo#85537
This commit is contained in:
+46
-7
@@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from contextlib import nullcontext
|
||||
import time
|
||||
import fnmatch
|
||||
import logging
|
||||
import optparse
|
||||
from unittest.mock import patch
|
||||
import odoo
|
||||
|
||||
from . import Command
|
||||
@@ -22,19 +24,28 @@ class Populate(Command):
|
||||
group.add_option("--models",
|
||||
dest='populate_models',
|
||||
help="Comma separated list of model or pattern (fnmatch)")
|
||||
group.add_option("--profile",
|
||||
dest='profiling_enabled', action="store_true",
|
||||
help="Specify if you want to profile records population.",
|
||||
default=False)
|
||||
group.add_option("--rollback",
|
||||
dest='populate_rollback', action="store_true",
|
||||
help="Specify if you want to rollback database population.",
|
||||
default=False)
|
||||
parser.add_option_group(group)
|
||||
opt = odoo.tools.config.parse_config(cmdargs)
|
||||
populate_models = opt.populate_models and set(opt.populate_models.split(','))
|
||||
population_size = opt.population_size
|
||||
dbname = odoo.tools.config['db_name']
|
||||
registry = odoo.registry(dbname)
|
||||
with registry.cursor() as cr:
|
||||
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
|
||||
self.populate(env, population_size, populate_models)
|
||||
|
||||
self.populate(
|
||||
env, opt.population_size, populate_models,
|
||||
profiling_enabled=opt.profiling_enabled,
|
||||
commit=not opt.populate_rollback)
|
||||
|
||||
@classmethod
|
||||
def populate(cls, env, size, model_patterns=False):
|
||||
def populate(cls, env, size, model_patterns=False, profiling_enabled=False, commit=True):
|
||||
registry = env.registry
|
||||
populated_models = None
|
||||
try:
|
||||
@@ -43,11 +54,37 @@ class Populate(Command):
|
||||
|
||||
_logger.log(25, 'Populating database')
|
||||
for model in ordered_models:
|
||||
if profiling_enabled:
|
||||
profiling_context = odoo.tools.profiler.Profiler(
|
||||
description=f'{model} {size}',
|
||||
db=env.cr.dbname
|
||||
)
|
||||
else:
|
||||
profiling_context = nullcontext()
|
||||
|
||||
if commit:
|
||||
commit_context = nullcontext()
|
||||
else:
|
||||
commit_context = patch('odoo.sql_db.Cursor.commit')
|
||||
|
||||
_logger.info('Populating database for model %s', model._name)
|
||||
t0 = time.time()
|
||||
registry.populated_models[model._name] = model._populate(size).ids
|
||||
# todo indicate somewhere that model is populated
|
||||
env.cr.commit()
|
||||
|
||||
with profiling_context, commit_context:
|
||||
registry.populated_models[model._name] = model._populate(size).ids
|
||||
|
||||
if not registry.populated_models[model._name]:
|
||||
# Do not create ir.profile records
|
||||
# for models without any population factories
|
||||
profiling_context.db = False
|
||||
|
||||
# force the flush to make sure population time still
|
||||
# considers flushing all values to database
|
||||
env['base'].flush()
|
||||
|
||||
if commit:
|
||||
env.cr.commit()
|
||||
|
||||
model_time = time.time() - t0
|
||||
if model_time > 1:
|
||||
_logger.info('Populated database for model %s (total: %fs) (average: %fms per record)',
|
||||
@@ -55,6 +92,8 @@ class Populate(Command):
|
||||
except:
|
||||
_logger.exception('Something went wrong populating database')
|
||||
finally:
|
||||
if not commit:
|
||||
env.cr.rollback()
|
||||
populated_models = registry.populated_models
|
||||
del registry.populated_models
|
||||
|
||||
|
||||
Reference in New Issue
Block a user