Skip to content

Commit 3eef414

Browse files
committed
[IMP] make odoo start up (much) faster
* to find out static file paths, instead of loading the manifest of all modules found on the addons_path, load them only as they are needed. this solves 3 problems: 1. it makes odoo start up much faster, as only the manifest of the modules of which static files are accessed are loaded instead of traversing the whole addons_path, searching for modules and loading all the manifest files. 2. it avoids a race condition at startup in threaded mode, where multiple threads access Application.statics while it has not been computed yet, resulting in each thread computing it, further slowing down the startup. 3. if the same module is available multiple times on the addons_path, the first one found will be used for static files instead of the last one found, what does not match the loading of the other files. * remove the default argument value of _get_manifest_cache() and fix calls to include the value, to be able to re-use the cached values instead of re-computing them without the argument.
1 parent 5018c0c commit 3eef414

3 files changed

Lines changed: 41 additions & 15 deletions

File tree

‎odoo/addons/base/models/ir_asset.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def process_path(directive, target, path_def):
202202

203203
# 2. Process all addons' manifests.
204204
for addon in self._topological_sort(tuple(addons)):
205-
for command in odoo.modules.module._get_manifest_cached(addon)['assets'].get(bundle, ()):
205+
for command in odoo.modules.module._get_manifest_cached(addon, None)['assets'].get(bundle, ()):
206206
directive, target, path_def = self._process_command(command)
207207
process_path(directive, target, path_def)
208208

@@ -257,7 +257,7 @@ def _topological_sort(self, addons_tuple):
257257
IrModule = self.env['ir.module.module']
258258

259259
def mapper(addon):
260-
manif = odoo.modules.module._get_manifest_cached(addon)
260+
manif = odoo.modules.module._get_manifest_cached(addon, None)
261261
from_terp = IrModule.get_values_from_terp(manif)
262262
from_terp['name'] = addon
263263
from_terp['depends'] = manif.get('depends', ['base'])
@@ -302,7 +302,7 @@ def _get_paths(self, path_def, installed, extensions=None):
302302
path_url = fs2web(path_def)
303303
path_parts = [part for part in path_url.split('/') if part]
304304
addon = path_parts[0]
305-
addon_manifest = odoo.modules.module._get_manifest_cached(addon)
305+
addon_manifest = odoo.modules.module._get_manifest_cached(addon, None)
306306

307307
safe_path = True
308308
if addon_manifest:

‎odoo/http.py‎

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@
159159

160160
import odoo
161161
from .exceptions import UserError, AccessError, AccessDenied
162-
from .modules.module import get_manifest
162+
from .modules.module import get_manifest, get_module_path
163163
from .modules.registry import Registry
164164
from .service import security, model as service_model
165165
from .tools import (config, consteq, date_utils, file_path, parse_version,
@@ -2117,6 +2117,41 @@ def _response(self, result=None, error=None):
21172117
return self.request.make_json_response(response)
21182118

21192119

2120+
class ModuleStaticPathMap:
2121+
def __init__(self):
2122+
self._static_path_map = {}
2123+
2124+
def get(self, module):
2125+
static_path = self._static_path_map.get(module)
2126+
if static_path:
2127+
return static_path
2128+
module_path = get_module_path(module)
2129+
if not module_path:
2130+
return None
2131+
# not passing module_path to get_manifest(), to take advantage of
2132+
# the cached values (in _get_manifest_cached()), as no code calls
2133+
# get_manifest() with a module_path.
2134+
manifest = get_manifest(module)
2135+
static_path = opj(module_path, "static")
2136+
if (
2137+
manifest
2138+
and (manifest["installable"] or manifest["assets"])
2139+
and os.path.isdir(static_path)
2140+
):
2141+
self._static_path_map[module] = static_path
2142+
return static_path
2143+
return None
2144+
2145+
def __getitem__(self, key):
2146+
static_path = self.get(key)
2147+
if static_path is not None:
2148+
return static_path
2149+
raise KeyError(key)
2150+
2151+
def __contains__(self, value):
2152+
return self.get(value) is not None
2153+
2154+
21202155
# =========================================================
21212156
# WSGI Entry Point
21222157
# =========================================================
@@ -2131,16 +2166,7 @@ def statics(self):
21312166
Map module names to their absolute ``static`` path on the file
21322167
system.
21332168
"""
2134-
mod2path = {}
2135-
for addons_path in odoo.addons.__path__:
2136-
for module in os.listdir(addons_path):
2137-
manifest = get_manifest(module)
2138-
static_path = opj(addons_path, module, 'static')
2139-
if (manifest
2140-
and (manifest['installable'] or manifest['assets'])
2141-
and os.path.isdir(static_path)):
2142-
mod2path[module] = static_path
2143-
return mod2path
2169+
return ModuleStaticPathMap()
21442170

21452171
def get_static_file(self, url, host=''):
21462172
"""

‎odoo/modules/module.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ def get_manifest(module, mod_path=None):
446446
return copy.deepcopy(_get_manifest_cached(module, mod_path))
447447

448448
@functools.lru_cache(maxsize=None)
449-
def _get_manifest_cached(module, mod_path=None):
449+
def _get_manifest_cached(module, mod_path):
450450
return load_manifest(module, mod_path)
451451

452452
def load_information_from_description_file(module, mod_path=None):

0 commit comments

Comments
 (0)