Skip to content

Commit 57874b6

Browse files
authored
fix: optimize TreeCommitHistory endpoint and add tree commits list view (#1877)
* Improve query performance for commit history * Include platform filter on query to speedup plot on hardware page * Add TreeCommitsListView and type models * Update frontend API and CommitNavigationGraph * Include tree_name and git_url on frontend requests
1 parent 16f80e4 commit 57874b6

25 files changed

Lines changed: 1395 additions & 120 deletions

File tree

backend/kernelCI_app/constants/localization.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ class DocStrings:
111111
TREE_LATEST_COMMIT_HASH_DESCRIPTION = "Commit hash to retrieve tree information"
112112
TREE_LATEST_ORIGIN_DESCRIPTION = "Origin filter to retrieve tree information"
113113

114+
TREE_LIST_COMMIT_HASH_DESCRIPTION = (
115+
"Comma-separated list of commit hashes to get history for"
116+
)
117+
114118
TREE_QUERY_ORIGIN_DESCRIPTION = "Origin of the tree"
115119
TREE_QUERY_GIT_URL_DESCRIPTION = "Git repository URL of the tree"
116120

backend/kernelCI_app/helpers/database.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,15 @@ def dict_fetchall(cursor) -> list[dict]:
66
"""
77
columns = [col[0] for col in cursor.description]
88
return [dict(zip(columns, row, strict=False)) for row in cursor.fetchall()]
9+
10+
11+
def debug_query(cursor, query, params) -> tuple[str, str]:
12+
sql = cursor.mogrify(query, params)
13+
profile = "\n".join(
14+
row for row, *_ in cursor.execute(f"EXPLAIN (ANALYZE, BUFFERS) {query}", params)
15+
)
16+
return (sql, profile)
17+
18+
19+
def print_debug_query(cursor, query, params):
20+
print("{}\n{}\n".format(*debug_query(cursor, query, params)))
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from typing import Optional
2+
3+
4+
def get_build_duration_clause(
5+
builds_duration: tuple[Optional[int], Optional[int]],
6+
) -> str:
7+
clause = ""
8+
duration_min, duration_max = builds_duration
9+
if duration_min is not None:
10+
clause += "AND builds.duration >= %(build_duration_min)s\n"
11+
if duration_max is not None:
12+
clause += "AND builds.duration <= %(build_duration_max)s\n"
13+
return clause
14+
15+
16+
def get_boot_test_duration_clause(
17+
boots_duration: tuple[Optional[int], Optional[int]],
18+
tests_duration: tuple[Optional[int], Optional[int]],
19+
) -> str:
20+
clause = ""
21+
duration_min, duration_max = tests_duration
22+
if duration_min is not None:
23+
clause += (
24+
"AND ((tests.path like 'boot.%%' or tests.path = 'boot') "
25+
"OR tests.duration >= %(test_duration_min)s)\n"
26+
)
27+
if duration_max is not None:
28+
clause += (
29+
"AND ((tests.path like 'boot.%%' or tests.path = 'boot') "
30+
"OR tests.duration <= %(test_duration_max)s)\n"
31+
)
32+
duration_min, duration_max = boots_duration
33+
if duration_min is not None:
34+
clause += (
35+
"AND (NOT (tests.path like 'boot.%%' or tests.path = 'boot') "
36+
"OR tests.duration >= %(boot_duration_min)s)\n"
37+
)
38+
if duration_max is not None:
39+
clause += (
40+
"AND (NOT (tests.path like 'boot.%%' or tests.path = 'boot') "
41+
"OR tests.duration <= %(boot_duration_max)s)\n"
42+
)
43+
return clause

backend/kernelCI_app/queries/hardware.py

Lines changed: 6 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
from kernelCI_app.cache import get_query_cache, set_query_cache
77
from kernelCI_app.helpers.database import dict_fetchall
8+
from kernelCI_app.queries.duration import (
9+
get_boot_test_duration_clause,
10+
get_build_duration_clause,
11+
)
812
from kernelCI_app.typeModels.hardwareDetails import CommitHead, Tree
913

1014

@@ -340,56 +344,6 @@ def get_hardware_details_data(
340344
return records
341345

342346

343-
def _get_build_duration_clause(
344-
builds_duration: tuple[Optional[int], Optional[int]],
345-
) -> str:
346-
clause = ""
347-
348-
# builds
349-
duration_min, duration_max = builds_duration
350-
if duration_min:
351-
clause += "AND builds.duration >= %(build_duration_min)s\n"
352-
if duration_max:
353-
clause += "AND builds.duration <= %(build_duration_max)s\n"
354-
355-
return clause
356-
357-
358-
def _get_boot_test_duration_clause(
359-
boots_duration: tuple[Optional[int], Optional[int]],
360-
tests_duration: tuple[Optional[int], Optional[int]],
361-
) -> str:
362-
clause = ""
363-
364-
# tests
365-
duration_min, duration_max = tests_duration
366-
if duration_min:
367-
clause += (
368-
"AND ((tests.path like 'boot.%%' or tests.path = 'boot') "
369-
"OR tests.duration >= %(test_duration_min)s)\n"
370-
)
371-
if duration_max:
372-
clause += (
373-
"AND ((tests.path like 'boot.%%' or tests.path = 'boot') "
374-
"OR tests.duration <= %(test_duration_max)s)\n"
375-
)
376-
377-
# boots
378-
duration_min, duration_max = boots_duration
379-
if duration_min:
380-
clause += (
381-
"AND (NOT (tests.path like 'boot.%%' or tests.path = 'boot') "
382-
"OR tests.duration >= %(boot_duration_min)s)\n"
383-
)
384-
if duration_max:
385-
clause += (
386-
"AND (NOT (tests.path like 'boot.%%' or tests.path = 'boot') "
387-
"OR tests.duration <= %(boot_duration_max)s)\n"
388-
)
389-
390-
return clause
391-
392-
393347
def get_hardware_details_summary(
394348
*,
395349
hardware_id: str,
@@ -427,8 +381,8 @@ def get_hardware_details_summary(
427381
if query_rows is not None:
428382
return query_rows
429383

430-
builds_duration_clause = _get_build_duration_clause(builds_duration)
431-
boots_tests_duration_clause = _get_boot_test_duration_clause(
384+
builds_duration_clause = get_build_duration_clause(builds_duration)
385+
boots_tests_duration_clause = get_boot_test_duration_clause(
432386
boots_duration, tests_duration
433387
)
434388

0 commit comments

Comments
 (0)