diff options
| author | Pimyn Girgis <pimyn@google.com> | 2025-12-16 11:04:05 +0100 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2026-01-08 08:55:35 +0000 |
| commit | c58cecdc85ba1bbd56a8c0aa39e0e03a34b0aba1 (patch) | |
| tree | 32f0acb58c9770779790fff11409da2d1f180875 /syz-cluster | |
| parent | 2a0332308e34a5854141928f86039764bcfa1023 (diff) | |
syz-cluster: add filtering by series and patch name
Update SeriesFilter in pkg/db to include PatchName and SeriesName fields, implement the SQL logic to filter by these
fields case-insensitively, and expose these filters in the dashboard UI.
Diffstat (limited to 'syz-cluster')
5 files changed, 45 insertions, 12 deletions
diff --git a/syz-cluster/dashboard/handler.go b/syz-cluster/dashboard/handler.go index d8ebd7c61..381efcfcd 100644 --- a/syz-cluster/dashboard/handler.go +++ b/syz-cluster/dashboard/handler.go @@ -117,6 +117,7 @@ func (h *dashboardHandler) seriesList(w http.ResponseWriter, r *http.Request) er WithFindings: r.FormValue("with_findings") != "", Limit: perPage, Offset: offset, + Name: r.FormValue("name"), }, // If the filters are changed, the old offset value is irrelevant. FilterFormURL: urlutil.DropParam(baseURL, "offset", ""), diff --git a/syz-cluster/dashboard/templates/index.html b/syz-cluster/dashboard/templates/index.html index b52da738f..afaa87d73 100644 --- a/syz-cluster/dashboard/templates/index.html +++ b/syz-cluster/dashboard/templates/index.html @@ -7,6 +7,10 @@ <input type="text" name="cc" class="form-control mb-3" value="{{.Filter.Cc}}" id="inputCc"> </div> <div class="col-auto col-sm-3"> + <label for="inputName">Patch/Series Name</label> + <input type="text" name="name" class="form-control mb-3" value="{{.Filter.Name}}" id="inputName"> + </div> + <div class="col-auto col-sm-3"> <label for="inputStatus">Status</label> <select id="inputStatus" class="form-control mb-3" name="status"> {{$filter := .Filter}} diff --git a/syz-cluster/pkg/db/migrations/8_add_series_and_patch_tokenization.down.sql b/syz-cluster/pkg/db/migrations/8_add_series_and_patch_tokenization.down.sql new file mode 100644 index 000000000..814f3d40e --- /dev/null +++ b/syz-cluster/pkg/db/migrations/8_add_series_and_patch_tokenization.down.sql @@ -0,0 +1,5 @@ +-- Revert search by patch and series names +DROP INDEX SeriesIndex; +ALTER TABLE Series DROP COLUMN TitleTokens; +DROP INDEX PatchesIndex; +ALTER TABLE Patches DROP COLUMN TitleTokens; diff --git a/syz-cluster/pkg/db/migrations/8_add_series_and_patch_tokenization.up.sql b/syz-cluster/pkg/db/migrations/8_add_series_and_patch_tokenization.up.sql new file mode 100644 index 000000000..b0a1b7afc --- /dev/null +++ b/syz-cluster/pkg/db/migrations/8_add_series_and_patch_tokenization.up.sql @@ -0,0 +1,5 @@ +-- Enable search by patch and series names +ALTER TABLE Series ADD COLUMN TitleTokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN; +CREATE SEARCH INDEX SeriesIndex ON Series(TitleTokens); +ALTER TABLE Patches ADD COLUMN TitleTokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN; +CREATE SEARCH INDEX PatchesIndex ON Patches(TitleTokens); diff --git a/syz-cluster/pkg/db/series_repo.go b/syz-cluster/pkg/db/series_repo.go index 0adbf3900..fdb452f72 100644 --- a/syz-cluster/pkg/db/series_repo.go +++ b/syz-cluster/pkg/db/series_repo.go @@ -9,6 +9,7 @@ import ( "context" "errors" "fmt" + "strings" "sync" "time" @@ -130,6 +131,7 @@ type SeriesFilter struct { WithFindings bool Limit int Offset int + Name string } // ListLatest() returns the list of series ordered by the decreasing PublishedAt value. @@ -139,41 +141,57 @@ func (repo *SeriesRepository) ListLatest(ctx context.Context, filter SeriesFilte defer ro.Close() stmt := spanner.Statement{ - SQL: "SELECT Series.* FROM Series WHERE 1=1", + SQL: "SELECT Series.* FROM Series", Params: map[string]any{}, } + var conds []string + if !maxPublishedAt.IsZero() { - stmt.SQL += " AND PublishedAt < @toTime" + conds = append(conds, "PublishedAt < @toTime") stmt.Params["toTime"] = maxPublishedAt } if filter.Cc != "" { - stmt.SQL += " AND @cc IN UNNEST(Cc)" + conds = append(conds, "@cc IN UNNEST(Cc)") stmt.Params["cc"] = filter.Cc } + if filter.Name != "" { + conds = append(conds, `ID IN( +SELECT ID FROM SERIES +WHERE SEARCH(Series.TitleTokens, @name) +UNION DISTINCT +SELECT SeriesID FROM Patches +WHERE SEARCH(Patches.TitleTokens, @name) +)`) + stmt.Params["name"] = filter.Name + } if filter.Status != SessionStatusAny { // It could have been an INNER JOIN in the main query, but let's favor the simpler code // in this function. // The optimizer should transform the query to a JOIN anyway. - stmt.SQL += " AND EXISTS(SELECT 1 FROM Sessions WHERE" + var statusCond = "EXISTS(SELECT 1 FROM Sessions WHERE" switch filter.Status { case SessionStatusWaiting: - stmt.SQL += " Sessions.SeriesID = Series.ID AND Sessions.StartedAt IS NULL" + statusCond += " Sessions.SeriesID = Series.ID AND Sessions.StartedAt IS NULL" case SessionStatusInProgress: - stmt.SQL += " Sessions.ID = Series.LatestSessionID AND Sessions.FinishedAt IS NULL" + statusCond += " Sessions.ID = Series.LatestSessionID AND Sessions.FinishedAt IS NULL" case SessionStatusFinished: - stmt.SQL += " Sessions.ID = Series.LatestSessionID AND Sessions.FinishedAt IS NOT NULL" + + statusCond += " Sessions.ID = Series.LatestSessionID AND Sessions.FinishedAt IS NOT NULL" + " AND Sessions.SkipReason IS NULL" case SessionStatusSkipped: - stmt.SQL += " Sessions.ID = Series.LatestSessionID AND Sessions.SkipReason IS NOT NULL" + statusCond += " Sessions.ID = Series.LatestSessionID AND Sessions.SkipReason IS NOT NULL" default: return nil, fmt.Errorf("unknown status value: %q", filter.Status) } - stmt.SQL += ")" + statusCond += ")" + conds = append(conds, statusCond) } if filter.WithFindings { - stmt.SQL += " AND Series.LatestSessionID IS NOT NULL AND EXISTS(" + - "SELECT 1 FROM Findings WHERE " + - "Findings.SessionID = Series.LatestSessionID AND Findings.InvalidatedAt IS NULL)" + conds = append(conds, "Series.LatestSessionID IS NOT NULL AND EXISTS("+ + "SELECT 1 FROM Findings WHERE "+ + "Findings.SessionID = Series.LatestSessionID AND Findings.InvalidatedAt IS NULL)") + } + if len(conds) != 0 { + stmt.SQL += " WHERE " + strings.Join(conds, " AND ") } stmt.SQL += " ORDER BY PublishedAt DESC, ID" if filter.Limit > 0 { |
