gitweb: Faster project search
authorJakub Narebski <jnareb@gmail.com>
Thu, 23 Feb 2012 15:54:48 +0000 (16:54 +0100)
committerJunio C Hamano <gitster@pobox.com>
Thu, 23 Feb 2012 20:53:03 +0000 (12:53 -0800)
Before searching by some field the information we search for must be
filled in, but we do not have to fill other fields that are not
involved in the search.

To be able to request filling only specified fields,
fill_project_list_info() was enhanced in previous commit to take
additional parameters which specify part of projects info to fill.
This way we can limit doing expensive calculations (like running
git-for-each-ref to get 'age' / "Last changed" info) to doing those
only for projects which we will show as search results.

This commit actually uses this interface, changing gitweb code from
the following behavior

  fill all project info on all projects
  search projects

to behaving like this pseudocode

  fill search fields on all projects
  search projects
  fill all project info on search results

With this commit the number of git commands used to generate search
results is 2*<matched projects> + 1, and depends on number of matched
projects rather than number of all projects (all repositories).

Note: this is 'git for-each-ref' to find last activity, and 'git config'
for each project, and 'git --version' once.

Example performance improvements, for search that selects 2
repositories out of 12 in total:

* Before (warm cache):
  "This page took 0.867151 seconds  and 27 git commands to generate."

* After (warm cache):
  "This page took 0.673643 seconds  and 5 git commands to generate."

Now imagine that they are 5 repositories out of 5000, and cold or
trashed cache case.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
gitweb/gitweb.perl

index 6794a1208af7cca8f737a1b0a1f15a145eaff44e..568b0775f2de72d7f4fe9b3d7f5f72cbc2108085 100755 (executable)
@@ -2987,6 +2987,10 @@ sub search_projects_list {
        return @$projlist
                unless ($tagfilter || $searchtext);
 
+       # searching projects require filling to be run before it;
+       fill_project_list_info($projlist,
+                              $tagfilter  ? 'ctags' : (),
+                              $searchtext ? ('path', 'descr') : ());
        my @projects;
  PROJECT:
        foreach my $pr (@$projlist) {
@@ -5387,12 +5391,13 @@ sub git_project_list_body {
        # filtering out forks before filling info allows to do less work
        @projects = filter_forks_from_projects_list(\@projects)
                if ($check_forks);
-       @projects = fill_project_list_info(\@projects);
-       # searching projects require filling to be run before it
+       # search_projects_list pre-fills required info
        @projects = search_projects_list(\@projects,
                                         'searchtext' => $searchtext,
                                         'tagfilter'  => $tagfilter)
                if ($tagfilter || $searchtext);
+       # fill the rest
+       @projects = fill_project_list_info(\@projects);
 
        $order ||= $default_projects_order;
        $from = 0 unless defined $from;