Merge pull request #327 from YunoHost/dont-take-lock-for-read-operations

Dont take lock for read/GET operations
This commit is contained in:
Alexandre Aubin 2023-01-05 19:15:20 +01:00 committed by GitHub
commit 9bc187d404
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 22 deletions

View file

@ -515,6 +515,8 @@ class ActionsMap:
tid = arguments.pop("_tid") tid = arguments.pop("_tid")
arguments = self.extraparser.parse_args(tid, arguments) arguments = self.extraparser.parse_args(tid, arguments)
want_to_take_lock = self.parser.want_to_take_lock(args, **kwargs)
# Retrieve action information # Retrieve action information
if len(tid) == 4: if len(tid) == 4:
namespace, category, subcategory, action = tid namespace, category, subcategory, action = tid
@ -537,7 +539,7 @@ class ActionsMap:
full_action_name = "{}.{}.{}".format(namespace, category, action) full_action_name = "{}.{}.{}".format(namespace, category, action)
# Lock the moulinette for the namespace # Lock the moulinette for the namespace
with MoulinetteLock(namespace, timeout, self.enable_lock): with MoulinetteLock(namespace, timeout, self.enable_lock and want_to_take_lock):
start = time() start = time()
try: try:
mod = __import__( mod = __import__(
@ -662,6 +664,14 @@ class ActionsMap:
if interface_type in authentication: if interface_type in authentication:
action_parser.authentication = authentication[interface_type] action_parser.authentication = authentication[interface_type]
# Disable the locking mechanism for all actions that are 'GET' actions on the api
routes = action_options.get("api")
routes = [routes] if isinstance(routes, str) else routes
if routes and all(route.startswith("GET ") for route in routes):
action_parser.want_to_take_lock = False
else:
action_parser.want_to_take_lock = True
# subcategory_name is like "cert" in "domain cert status" # subcategory_name is like "cert" in "domain cert status"
# subcategory_values is the values of this subcategory (like actions) # subcategory_values is the values of this subcategory (like actions)
for subcategory_name, subcategory_values in subcategories.items(): for subcategory_name, subcategory_values in subcategories.items():
@ -705,5 +715,13 @@ class ActionsMap:
if interface_type in authentication: if interface_type in authentication:
action_parser.authentication = authentication[interface_type] action_parser.authentication = authentication[interface_type]
# Disable the locking mechanism for all actions that are 'GET' actions on the api
routes = action_options.get("api")
routes = [routes] if isinstance(routes, str) else routes
if routes and all(route.startswith("GET ") for route in routes):
action_parser.want_to_take_lock = False
else:
action_parser.want_to_take_lock = True
logger.debug("building parser took %.3fs", time() - start) logger.debug("building parser took %.3fs", time() - start)
return top_parser return top_parser

View file

@ -5,12 +5,11 @@ import logging
import argparse import argparse
import copy import copy
import datetime import datetime
from collections import deque, OrderedDict from collections import OrderedDict
from json.encoder import JSONEncoder from json.encoder import JSONEncoder
from typing import Optional from typing import Optional
from moulinette import m18n from moulinette import m18n
from moulinette.core import MoulinetteError
logger = logging.getLogger("moulinette.interface") logger = logging.getLogger("moulinette.interface")

View file

@ -647,6 +647,12 @@ class ActionsMapParser(BaseActionsMapParser):
return parser.authentication return parser.authentication
def want_to_take_lock(self, _, route):
_, parser = self._parsers[route]
return getattr(parser, "want_to_take_lock", True)
def parse_args(self, args, **kwargs): def parse_args(self, args, **kwargs):
"""Parse arguments """Parse arguments

View file

@ -397,25 +397,9 @@ class ActionsMapParser(BaseActionsMapParser):
) )
def auth_method(self, args): def auth_method(self, args):
# FIXME? idk .. this try/except is duplicated from parse_args below
# Just to be able to obtain the tid
try:
ret = self._parser.parse_args(args)
except SystemExit:
raise
except Exception as e:
error_message = "unable to parse arguments '{}' because: {}".format(
" ".join(args),
e,
)
logger.exception(error_message)
raise MoulinetteValidationError(error_message, raw_msg=True)
tid = getattr(ret, "_tid", None) ret = self.parse_args(args)
tid = getattr(ret, "_tid", [])
# Ugh that's for yunohost --version ...
if tid is None:
return None
# We go down in the subparser tree until we find the leaf # We go down in the subparser tree until we find the leaf
# corresponding to the tid with a defined authentication # corresponding to the tid with a defined authentication
@ -443,6 +427,17 @@ class ActionsMapParser(BaseActionsMapParser):
logger.exception(error_message) logger.exception(error_message)
raise MoulinetteValidationError(error_message, raw_msg=True) raise MoulinetteValidationError(error_message, raw_msg=True)
def want_to_take_lock(self, args):
ret = self.parse_args(args)
tid = getattr(ret, "_tid", [])
if len(tid) == 3:
_p = self._subparsers.choices[tid[1]]._actions[1].choices[tid[2]]
elif len(tid) == 4:
_p = self._subparsers.choices[tid[1]]._actions[1].choices[tid[2]]._actions[1].choices[tid[3]]
return getattr(_p, "want_to_take_lock", True)
class Interface: class Interface:

View file

@ -4,5 +4,7 @@ ignore =
E128, E128,
E731, E731,
E722, E722,
# Black formatter conflict
W503, W503,
E203 # Black formatter conflict
E203