[autotest] limit the size of the get_num_jobs query
get_num_jobs query has the potential to be very expensive, and is
emitted by the web afe. This modification puts a cap on the number of
jobs that will be inspected for the count, and thus a cap on the count.
BUG=chromium:599267
TEST=local autotest
Change-Id: I8e7f3a6711807732a0ac3de93860ee40dac6b53c
Reviewed-on: https://chromium-review.googlesource.com/336807
Commit-Ready: Fang Deng <fdeng@chromium.org>
Tested-by: Fang Deng <fdeng@chromium.org>
Reviewed-by: Aviv Keshet <akeshet@chromium.org>
diff --git a/frontend/afe/rpc_interface.py b/frontend/afe/rpc_interface.py
index 01ada70..1592088 100644
--- a/frontend/afe/rpc_interface.py
+++ b/frontend/afe/rpc_interface.py
@@ -35,6 +35,7 @@
import datetime
import logging
+from django.db import connections
from django.db.models import Count
import common
from autotest_lib.client.common_lib import priorities
@@ -1161,9 +1162,17 @@
def get_num_jobs(not_yet_run=False, running=False, finished=False,
suite=False, sub=False, standalone=False,
+ max_search_count=9999,
**filter_data):
- """\
- See get_jobs() for documentation of extra filter parameters.
+ """See get_jobs() for documentation of extra filter parameters.
+
+ This method returns the number of jobs that match the filter, or 9999
+ whichever is less.
+
+ @params: max_search_count: Default 9999. If None, return accurate job count.
+ Limit the maximum number of jobs we inspect, since this query examines the
+ afe_host_queue_entries table as well and can be quite expensive if there
+ are a lot of jobs. See crbug.com/599267
"""
extra_args = rpc_utils.extra_job_status_filters(not_yet_run,
running,
@@ -1172,8 +1181,19 @@
suite,
sub,
standalone)
- return models.Job.query_count(filter_data)
+ if max_search_count is None:
+ return models.Job.query_count(filter_data)
+ # We need to quote the string as django may not quote it properly.
+ for key, val in filter_data.iteritems():
+ if isinstance(val, str):
+ filter_data[key] = repr(val)
+ inner_query = str(models.Job.query_objects(filter_data)[:max_search_count].query)
+ full_query = 'SELECT COUNT(*) FROM (%s) t' % inner_query
+ cursor = connections['default'].cursor()
+ cursor.execute(full_query)
+ row = cursor.fetchone()
+ return row[0]
def get_jobs_summary(**filter_data):
"""\