From 8ff10828c634f245aa753ea3683fd79c1231b5f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 23 May 2016 15:18:23 +0200 Subject: [PATCH] Cache (project_id, node_type_name) -> project mapping per request. When returning many nodes of the same project and same node type, this prevents us from doing the same request over and over to MongoDB, increasing performance. --- pillar/application/utils/authorization.py | 36 ++++++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/pillar/application/utils/authorization.py b/pillar/application/utils/authorization.py index 3929b677..96268d65 100644 --- a/pillar/application/utils/authorization.py +++ b/pillar/application/utils/authorization.py @@ -107,8 +107,6 @@ def has_permissions(collection_name, resource, method, append_allowed_methods=Fa def compute_aggr_permissions(collection_name, resource, check_node_type): """Returns a permissions dict.""" - projects_collection = current_app.data.driver.db['projects'] - # We always need the know the project. if collection_name == 'projects': project = resource @@ -126,12 +124,8 @@ def compute_aggr_permissions(collection_name, resource, check_node_type): # embedded project project = resource['project'] else: - project = projects_collection.find_one( - ObjectId(resource['project']), - {'permissions': 1, - 'node_types': {'$elemMatch': {'name': node_type_name}}, - 'node_types.name': 1, - 'node_types.permissions': 1}) + project_id = resource['project'] + project = _find_project_node_type(project_id, node_type_name) # Every node should have a project. if project is None: @@ -157,6 +151,32 @@ def compute_aggr_permissions(collection_name, resource, check_node_type): return merge_permissions(project_permissions, node_type_permissions, node_permissions) +def _find_project_node_type(project_id, node_type_name): + """Returns the project with just the one named node type.""" + + # Cache result per request, as many nodes of the same project can be checked. + cache = g.get('_find_project_node_type_cache') + if cache is None: + cache = g._find_project_node_type_cache = {} + + try: + return cache[(project_id, node_type_name)] + except KeyError: + pass + + projects_collection = current_app.data.driver.db['projects'] + project = projects_collection.find_one( + ObjectId(project_id), + {'permissions': 1, + 'node_types': {'$elemMatch': {'name': node_type_name}}, + 'node_types.name': 1, + 'node_types.permissions': 1}) + + cache[(project_id, node_type_name)] = project + + return project + + def merge_permissions(*args): """Merges all given permissions.