From: Dennis Kaarsemaker Date: Fri, 3 Aug 2012 09:55:49 +0000 (+0200) Subject: Massive tree action speedup X-Git-Tag: 0.004002~4^2 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FGitalist.git;a=commitdiff_plain;h=eb8ee28a1c14382122949c6dcc09bc3ee6a08310 Massive tree action speedup The tree action used to use $tree_obj->tree to get all tree entries. This is ridiculously slow as it loads all blobs via git cat-file. Instead, expose directory_entries from the underlying Git::PurePerl object and use it instead. This also required moving _mode_str (now mode_string for consistency) to Gitalist::Utils so it could be used in the template. --- diff --git a/lib/Gitalist/Controller/Fragment/Ref.pm b/lib/Gitalist/Controller/Fragment/Ref.pm index cbfacda..bc79659 100644 --- a/lib/Gitalist/Controller/Fragment/Ref.pm +++ b/lib/Gitalist/Controller/Fragment/Ref.pm @@ -54,7 +54,7 @@ after tree => sub { ; $c->stash( tree => $tree_obj, - tree_list => $tree_obj->tree, + entries => $tree_obj->entries, ); }; diff --git a/lib/Gitalist/Controller/Root.pm b/lib/Gitalist/Controller/Root.pm index 7b921f8..42896ea 100644 --- a/lib/Gitalist/Controller/Root.pm +++ b/lib/Gitalist/Controller/Root.pm @@ -3,7 +3,7 @@ package Gitalist::Controller::Root; use Moose; use Moose::Autobox; use Digest::MD5 qw(md5_hex); -use Gitalist::Utils qw/ age_string /; +use Gitalist::Utils qw/ age_string mode_string /; use namespace::autoclean; @@ -54,6 +54,9 @@ sub base : Chained('/root') PathPart('') CaptureArgs(0) { $uri .= "?s=$size" if $size; return $uri; }, + mode_string => sub { + return mode_string(oct shift); + } ); } diff --git a/lib/Gitalist/Git/Object.pm b/lib/Gitalist/Git/Object.pm index 7d46632..c4e87d4 100644 --- a/lib/Gitalist/Git/Object.pm +++ b/lib/Gitalist/Git/Object.pm @@ -6,6 +6,7 @@ class Gitalist::Git::Object with Gitalist::Git::Serializable is dirty { use MooseX::Types::Moose qw/Str Int Bool Maybe ArrayRef/; use MooseX::Types::Common::String qw/NonEmptySimpleStr/; + use Gitalist::Utils qw/mode_string/; use overload '""' => '_to_string', fallback => 1; # repository and sha1 are required initargs @@ -74,41 +75,7 @@ class Gitalist::Git::Object with Gitalist::Git::Serializable is dirty { } method _build_modestr { - return _mode_str($self->mode); - } - - # via gitweb.pm circa line 1305 - use Fcntl ':mode'; - use constant { - S_IFINVALID => 0030000, - S_IFGITLINK => 0160000, - }; - - # submodule/subrepository, a commit object reference - sub S_ISGITLINK($) { - return (($_[0] & S_IFMT) == S_IFGITLINK) - } - - # convert file mode in octal to symbolic file mode string - sub _mode_str { - my $mode = shift; - - if (S_ISGITLINK($mode)) { - return 'm---------'; - } elsif (S_ISDIR($mode & S_IFMT)) { - return 'drwxr-xr-x'; - } elsif ($^O ne 'MSWin32' and S_ISLNK($mode)) { # this is ENOLINKS country, we can't stop here! - return 'lrwxrwxrwx'; - } elsif (S_ISREG($mode)) { - # git cares only about the executable bit - if ($mode & S_IXUSR) { - return '-rwxr-xr-x'; - } else { - return '-rw-r--r--'; - } - } else { - return '----------'; - } + return mode_string($self->mode); } } # end class diff --git a/lib/Gitalist/Git/Object/HasTree.pm b/lib/Gitalist/Git/Object/HasTree.pm index 9421c77..6e1b4fe 100644 --- a/lib/Gitalist/Git/Object/HasTree.pm +++ b/lib/Gitalist/Git/Object/HasTree.pm @@ -29,6 +29,10 @@ role Gitalist::Git::Object::HasTree { return \@ret; } + method entries { + return $self->{_gpp_obj}->{directory_entries}; + } + } 1; diff --git a/lib/Gitalist/Utils.pm b/lib/Gitalist/Utils.pm index f11dc34..6d32446 100644 --- a/lib/Gitalist/Utils.pm +++ b/lib/Gitalist/Utils.pm @@ -5,6 +5,7 @@ use Exporter qw/import/; our @EXPORT_OK = qw/ age_string + mode_string /; sub age_string { @@ -50,6 +51,40 @@ sub is_binary { return $_[0] !~ /^[[:print:]]+$ (?: \s ^[[:print:]]+$ )?/mx; } +# via gitweb.pm circa line 1305 +use Fcntl ':mode'; +use constant { + S_IFINVALID => 0030000, + S_IFGITLINK => 0160000, +}; + +# submodule/subrepository, a commit object reference +sub S_ISGITLINK($) { + return (($_[0] & S_IFMT) == S_IFGITLINK) +} + +# convert file mode in octal to symbolic file mode string +sub mode_string { + my $mode = shift; + + if (S_ISGITLINK($mode)) { + return 'm---------'; + } elsif (S_ISDIR($mode & S_IFMT)) { + return 'drwxr-xr-x'; + } elsif ($^O ne 'MSWin32' and S_ISLNK($mode)) { # this is ENOLINKS country, we can't stop here! + return 'lrwxrwxrwx'; + } elsif (S_ISREG($mode)) { + # git cares only about the executable bit + if ($mode & S_IXUSR) { + return '-rwxr-xr-x'; + } else { + return '-rw-r--r--'; + } + } else { + return '----------'; + } +} + 1; __END__ diff --git a/root/fragment/ref/tree.tt2 b/root/fragment/ref/tree.tt2 index d83e358..f2d63a5 100755 --- a/root/fragment/ref/tree.tt2 +++ b/root/fragment/ref/tree.tt2 @@ -13,8 +13,8 @@ # sort files and folders SET tree_files = []; SET tree_folders = []; - FOREACH item IN tree_list; - IF item.type == "blob"; + FOREACH item IN entries; + IF item.mode != "40000"; tree_files.push(item); ELSE; tree_folders.push(item); @@ -23,25 +23,25 @@ %] [% BLOCK output_tree %] - [% FOREACH item IN tree_type.sort('file') %] + [% FOREACH item IN tree_type.sort('filename') %] - [% item.modestr %] + [% c.stash.mode_string(item.mode) %] [%- - action_type = item.type == 'tree' ? 'tree' : 'blob'; - action_for_link = item.type == 'tree' ? '/ref/tree' : '/ref/blob'; - blob_or_tree_link = c.uri_for_action(action_for_link, c.req.captures, c.req.args.to_path(item.file)) + action_type = item.mode == '40000' ? 'tree' : 'blob'; + action_for_link = item.mode == '40000' ? '/ref/tree' : '/ref/blob'; + blob_or_tree_link = c.uri_for_action(action_for_link, c.req.captures, c.req.args.to_path(item.filename)) -%] - [% item.file %] + [% item.filename %] [% theact %] - [% IF item.type == 'blob' %] - Blob - raw - blame + [% IF item.mode != '40000' %] + Blob + raw + blame [% END %] - Short log + Short log - [% c.req.args.to_path(item.file) %]Loading commit info ... + [% c.req.args.to_path(item.filename) %]Loading commit info ... [% counter = counter + 1 %] [% END %]