[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:
Victor Feyens
2022-05-19 18:06:05 +02:00
parent c7072eaba6
commit 695ab84f63
+46 -7
View File
@@ -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